feat(telemetry): implement glitchtip/sentry integration with smart proxy
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 2m43s
Build & Deploy / 🏗️ Build (push) Failing after 5m34s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 2m43s
Build & Deploy / 🏗️ Build (push) Failing after 5m34s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
- Added Sentry/GlitchTip relay route handler - Configured Sentry for client (with tunnel), server, and edge runtimes - Refactored GlitchTip adapter to use official @sentry/nextjs SDK - Fixed ComparisonRow type issues and Analytics Suspense bailout - Integrated Sentry instrumentation into the boot sequence
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, Suspense } from "react";
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { ScrollDepthTracker } from "./analytics/ScrollDepthTracker";
|
||||
import { getDefaultAnalytics } from "../utils/analytics";
|
||||
import { getDefaultErrorTracking } from "../utils/error-tracking";
|
||||
|
||||
export const Analytics: React.FC = () => {
|
||||
const AnalyticsInner: React.FC = () => {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
@@ -122,17 +122,23 @@ export const Analytics: React.FC = () => {
|
||||
const adapter = analytics.getAdapter();
|
||||
const scriptTag = adapter.getScriptTag ? adapter.getScriptTag() : null;
|
||||
|
||||
if (!scriptTag) return null;
|
||||
|
||||
// We use dangerouslySetInnerHTML to inject the script tag from the adapter
|
||||
// This is safe here because the script URLs and IDs come from our own config/env
|
||||
return (
|
||||
<>
|
||||
<ScrollDepthTracker />
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: scriptTag }}
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
{scriptTag && (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{ __html: scriptTag }}
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Analytics: React.FC = () => {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<AnalyticsInner />
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { cn } from "../../utils/cn";
|
||||
interface ComparisonRowProps {
|
||||
description?: string;
|
||||
negativeLabel: string;
|
||||
negativeText: React.ReactNode;
|
||||
negativeText: string;
|
||||
positiveLabel: string;
|
||||
positiveText: React.ReactNode;
|
||||
reverse?: boolean;
|
||||
|
||||
@@ -20,6 +20,9 @@ const envExtension = {
|
||||
.url()
|
||||
.optional()
|
||||
.default("https://analytics.infra.mintel.me"),
|
||||
|
||||
// Error Tracking
|
||||
SENTRY_DSN: z.string().url().optional(),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,76 +1,48 @@
|
||||
/**
|
||||
* GlitchTip Error Tracking Adapter
|
||||
* GlitchTip is Sentry-compatible.
|
||||
* This version uses the official @sentry/nextjs SDK.
|
||||
*/
|
||||
|
||||
import type { ErrorTrackingAdapter, ErrorContext, ErrorTrackingConfig } from './interfaces';
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import type {
|
||||
ErrorTrackingAdapter,
|
||||
ErrorContext,
|
||||
ErrorTrackingConfig,
|
||||
} from "./interfaces";
|
||||
|
||||
export class GlitchTipAdapter implements ErrorTrackingAdapter {
|
||||
private dsn: string;
|
||||
|
||||
constructor(config: ErrorTrackingConfig) {
|
||||
this.dsn = config.dsn;
|
||||
this.init(config);
|
||||
}
|
||||
|
||||
private init(config: ErrorTrackingConfig) {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
// In a real scenario, we would import @sentry/nextjs or @sentry/browser
|
||||
// For this implementation, we assume Sentry is available globally or
|
||||
// we provide the structure that would call the SDK.
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.init({
|
||||
dsn: this.dsn,
|
||||
environment: config.environment || 'production',
|
||||
release: config.release,
|
||||
debug: config.debug || false,
|
||||
});
|
||||
}
|
||||
constructor(_config: ErrorTrackingConfig) {
|
||||
// Sentry is initialized via sentry.*.config.ts files
|
||||
}
|
||||
|
||||
captureException(error: any, context?: ErrorContext): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.captureException(error, context);
|
||||
} else {
|
||||
console.error('[GlitchTip] Exception captured (Sentry not loaded):', error, context);
|
||||
}
|
||||
Sentry.captureException(error, {
|
||||
extra: context?.extra,
|
||||
tags: context?.tags,
|
||||
user: context?.user as any,
|
||||
level: context?.level as any,
|
||||
});
|
||||
}
|
||||
|
||||
captureMessage(message: string, context?: ErrorContext): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.captureMessage(message, context);
|
||||
} else {
|
||||
console.log('[GlitchTip] Message captured (Sentry not loaded):', message, context);
|
||||
}
|
||||
Sentry.captureMessage(message, {
|
||||
extra: context?.extra,
|
||||
tags: context?.tags,
|
||||
user: context?.user as any,
|
||||
level: context?.level as any,
|
||||
});
|
||||
}
|
||||
|
||||
setUser(user: ErrorContext['user']): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.setUser(user);
|
||||
}
|
||||
setUser(user: ErrorContext["user"]): void {
|
||||
Sentry.setUser(user as any);
|
||||
}
|
||||
|
||||
setTag(key: string, value: string): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.setTag(key, value);
|
||||
}
|
||||
Sentry.setTag(key, value);
|
||||
}
|
||||
|
||||
setExtra(key: string, value: any): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
const w = window as any;
|
||||
if (w.Sentry) {
|
||||
w.Sentry.setExtra(key, value);
|
||||
}
|
||||
Sentry.setExtra(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user