@od-oneapp/observability 2026.1.1301
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +523 -0
- package/dist/client-next.d.mts +20 -0
- package/dist/client-next.d.mts.map +1 -0
- package/dist/client-next.mjs +64 -0
- package/dist/client-next.mjs.map +1 -0
- package/dist/client.d.mts +11 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +47 -0
- package/dist/client.mjs.map +1 -0
- package/dist/env.d.mts +15 -0
- package/dist/env.d.mts.map +1 -0
- package/dist/env.mjs +45 -0
- package/dist/env.mjs.map +1 -0
- package/dist/factory-DkY353r8.mjs +380 -0
- package/dist/factory-DkY353r8.mjs.map +1 -0
- package/dist/hooks-useObservability.d.mts +11 -0
- package/dist/hooks-useObservability.d.mts.map +1 -0
- package/dist/hooks-useObservability.mjs +174 -0
- package/dist/hooks-useObservability.mjs.map +1 -0
- package/dist/index-CpcdzWrF.d.mts +24 -0
- package/dist/index-CpcdzWrF.d.mts.map +1 -0
- package/dist/index.d.mts +88 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +97 -0
- package/dist/index.mjs.map +1 -0
- package/dist/manager-BxQqOPEg.d.mts +33 -0
- package/dist/manager-BxQqOPEg.d.mts.map +1 -0
- package/dist/plugin-Bfq-o3nr.d.mts +60 -0
- package/dist/plugin-Bfq-o3nr.d.mts.map +1 -0
- package/dist/plugin-Bt-ygG1m.d.mts +254 -0
- package/dist/plugin-Bt-ygG1m.d.mts.map +1 -0
- package/dist/plugin-CLFwRERa.mjs +593 -0
- package/dist/plugin-CLFwRERa.mjs.map +1 -0
- package/dist/plugin-CP895lBx.mjs +534 -0
- package/dist/plugin-CP895lBx.mjs.map +1 -0
- package/dist/plugin-CaQxviDs.d.mts +61 -0
- package/dist/plugin-CaQxviDs.d.mts.map +1 -0
- package/dist/plugin-lPdJirTY.mjs +234 -0
- package/dist/plugin-lPdJirTY.mjs.map +1 -0
- package/dist/plugins-betterstack-env.d.mts +29 -0
- package/dist/plugins-betterstack-env.d.mts.map +1 -0
- package/dist/plugins-betterstack-env.mjs +75 -0
- package/dist/plugins-betterstack-env.mjs.map +1 -0
- package/dist/plugins-betterstack.d.mts +4 -0
- package/dist/plugins-betterstack.mjs +4 -0
- package/dist/plugins-console.d.mts +37 -0
- package/dist/plugins-console.d.mts.map +1 -0
- package/dist/plugins-console.mjs +196 -0
- package/dist/plugins-console.mjs.map +1 -0
- package/dist/plugins-sentry-env.d.mts +37 -0
- package/dist/plugins-sentry-env.d.mts.map +1 -0
- package/dist/plugins-sentry-env.mjs +79 -0
- package/dist/plugins-sentry-env.mjs.map +1 -0
- package/dist/plugins-sentry-microfrontend-env.d.mts +49 -0
- package/dist/plugins-sentry-microfrontend-env.d.mts.map +1 -0
- package/dist/plugins-sentry-microfrontend-env.mjs +80 -0
- package/dist/plugins-sentry-microfrontend-env.mjs.map +1 -0
- package/dist/plugins-sentry-microfrontend.d.mts +2 -0
- package/dist/plugins-sentry-microfrontend.mjs +3 -0
- package/dist/plugins-sentry.d.mts +5 -0
- package/dist/plugins-sentry.mjs +6 -0
- package/dist/server-edge.d.mts +15 -0
- package/dist/server-edge.d.mts.map +1 -0
- package/dist/server-edge.mjs +53 -0
- package/dist/server-edge.mjs.map +1 -0
- package/dist/server-next.d.mts +17 -0
- package/dist/server-next.d.mts.map +1 -0
- package/dist/server-next.mjs +64 -0
- package/dist/server-next.mjs.map +1 -0
- package/dist/server.d.mts +11 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +48 -0
- package/dist/server.mjs.map +1 -0
- package/dist/utils-CuGrTcD6.d.mts +77 -0
- package/dist/utils-CuGrTcD6.d.mts.map +1 -0
- package/env.ts +67 -0
- package/package.json +147 -0
- package/src/client-next.ts +131 -0
- package/src/client.ts +70 -0
- package/src/core/index.ts +15 -0
- package/src/core/manager.ts +361 -0
- package/src/core/plugin.ts +61 -0
- package/src/core/types.ts +151 -0
- package/src/factory/builder.ts +132 -0
- package/src/factory/index.ts +67 -0
- package/src/factory/presets.ts +78 -0
- package/src/hooks/useObservability.ts +206 -0
- package/src/plugins/betterstack/env.ts +101 -0
- package/src/plugins/betterstack/index.ts +15 -0
- package/src/plugins/betterstack/plugin.ts +373 -0
- package/src/plugins/console/index.ts +323 -0
- package/src/plugins/sentry/__tests__/plugin-tracing.test.ts +511 -0
- package/src/plugins/sentry/env.ts +93 -0
- package/src/plugins/sentry/index.ts +28 -0
- package/src/plugins/sentry/plugin.ts +953 -0
- package/src/plugins/sentry/types.ts +252 -0
- package/src/plugins/sentry-microfrontend/env.ts +105 -0
- package/src/plugins/sentry-microfrontend/index.ts +12 -0
- package/src/plugins/sentry-microfrontend/multiplexed-transport.ts +221 -0
- package/src/plugins/sentry-microfrontend/plugin.ts +500 -0
- package/src/plugins/sentry-microfrontend/sentry-types.ts +140 -0
- package/src/plugins/sentry-microfrontend/types.ts +130 -0
- package/src/plugins/sentry-microfrontend/utils.ts +326 -0
- package/src/server-edge.ts +113 -0
- package/src/server-next.ts +114 -0
- package/src/server.ts +71 -0
- package/src/shared.ts +148 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-CP895lBx.mjs","names":[],"sources":["../src/plugins/sentry/plugin.ts"],"sourcesContent":["/**\n * @fileoverview Sentry plugin implementation\n * Sentry plugin implementation\n */\n\nimport { logDebug, logError, logWarn } from '@repo/shared/logger';\nimport type { ObservabilityServerPlugin } from '../../core/plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityUser,\n} from '../../core/types';\nimport { isBrowser } from '../../shared';\nimport { safeEnv } from './env';\nimport type { Hub, Scope, Span, SpanContext, Transaction, TransactionContext } from './types';\n\n/**\n * Default log filter function that filters out noisy development logs.\n * Filters out:\n * - Next.js Fast Refresh messages\n * - HMR (Hot Module Replacement) messages\n * - Prisma query logs (server-only)\n * - Prisma engine/info logs\n * - SQL queries matching Prisma's format\n *\n * Handles ANSI color codes, console formatting (%c, %s), and CSS styling.\n *\n * @param log - The log entry from Sentry\n * @param isServer - Whether this is running on the server (defaults to true)\n * @returns The log entry if it should be sent, or null to filter it out\n */\nexport function defaultBeforeSendLog(log: any, isServer = true): any | null {\n // Check both message and any formatted message fields\n const messageToCheck = log.message || log.formatted || '';\n if (!messageToCheck) {\n return log; // No message to filter, send as-is\n }\n\n const message = String(messageToCheck);\n\n // Remove ANSI color codes for comparison (e.g., \\u001b[34mprisma:query\\u001b[39m)\n // Also handle %c format codes used by console styling and %s placeholders\n const messageWithoutAnsi = message\n .replace(/\\u001b\\[[0-9;]*m/g, '') // Remove ANSI escape codes\n .replace(/%[csdfiO]/g, '') // Remove console format placeholders (%c, %s, %d, %f, %i, %o)\n .replace(/background:[^;]+;?/g, '') // Remove CSS background styles\n .replace(/color:[^;]+;?/g, '') // Remove CSS color styles\n .replace(/border-radius:[^;]+;?/g, '') // Remove CSS border-radius\n .replace(/light-dark\\([^)]+\\)/g, '') // Remove light-dark() CSS functions\n .replace(/rgba?\\([^)]+\\)/g, '') // Remove rgba/rgb color functions\n .replace(/#[0-9a-fA-F]{3,8}/g, '') // Remove hex colors\n .toLowerCase(); // Case-insensitive matching\n\n // Filter out Next.js Fast Refresh and HMR messages (both client and server)\n if (messageWithoutAnsi.includes('[fast refresh]') || messageWithoutAnsi.includes('[hmr]')) {\n return null; // Drop the log\n }\n\n // Filter out Prisma logs (server-only)\n if (isServer) {\n if (\n messageWithoutAnsi.includes('prisma:query') ||\n messageWithoutAnsi.includes('prisma:engine') ||\n messageWithoutAnsi.includes('prisma:info') ||\n // Also filter SQL queries that look like Prisma queries (SELECT ... FROM \"public\".)\n (messageWithoutAnsi.includes('select') &&\n messageWithoutAnsi.includes('from') &&\n (messageWithoutAnsi.includes('\"public\".') || messageWithoutAnsi.includes('public.')))\n ) {\n return null; // Drop the log\n }\n }\n\n return log; // Send the log\n}\n\n/**\n * Minimal Sentry interface for common methods across all Sentry packages\n */\ninterface SentryClient {\n init(options: any): void;\n captureException(error: any, captureContext?: any): string;\n captureMessage(message: string, captureContext?: any): string;\n setUser(user: any): void;\n addBreadcrumb(breadcrumb: any): void;\n withScope(callback: (scope: any) => void): void;\n getCurrentScope?(): any;\n getActiveTransaction?(): any;\n startTransaction?(context: TransactionContext, customSamplingContext?: any): any;\n startSpan?(context: SpanContext): any;\n configureScope?(callback: (scope: any) => void): void;\n getCurrentHub?(): any;\n flush?(timeout?: number): Promise<boolean>;\n close?(timeout?: number): Promise<boolean>;\n browserTracingIntegration?(): any;\n replayIntegration?(): any;\n profilesIntegration?(): any;\n consoleLoggingIntegration?(options?: { levels?: string[] }): any;\n logger?: {\n trace(message: string, attributes?: Record<string, unknown>): void;\n debug(message: string, attributes?: Record<string, unknown>): void;\n info(message: string, attributes?: Record<string, unknown>): void;\n warn(message: string, attributes?: Record<string, unknown>): void;\n error(message: string, attributes?: Record<string, unknown>): void;\n fatal(message: string, attributes?: Record<string, unknown>): void;\n fmt(strings: TemplateStringsArray, ...values: unknown[]): string;\n };\n}\n\n/**\n * Sentry plugin configuration\n */\nexport interface SentryPluginConfig {\n /**\n * The Sentry package to use (e.g., '@sentry/node', '@sentry/browser', '@sentry/nextjs')\n * If not provided, the plugin will try to detect based on environment\n */\n sentryPackage?: string;\n\n // Core Sentry options\n dsn?: string;\n environment?: string;\n release?: string;\n enabled?: boolean;\n debug?: boolean;\n\n // Sampling rates\n tracesSampleRate?: number;\n profilesSampleRate?: number;\n replaysSessionSampleRate?: number;\n replaysOnErrorSampleRate?: number;\n\n // Integrations and hooks\n integrations?: any[];\n beforeSend?: (event: any, hint: any) => any;\n beforeSendTransaction?: (event: any, hint: any) => any;\n beforeBreadcrumb?: (breadcrumb: any, hint?: any) => any;\n beforeSendLog?: (log: any) => any;\n\n // Logging options\n enableLogs?: boolean;\n consoleLoggingIntegration?: {\n levels?: ('log' | 'warn' | 'error' | 'debug' | 'info' | 'assert' | 'trace')[];\n };\n\n // Trace propagation\n tracePropagationTargets?: (string | RegExp)[];\n\n // Other options\n initialScope?: any;\n maxBreadcrumbs?: number;\n attachStacktrace?: boolean;\n autoSessionTracking?: boolean;\n sendDefaultPii?: boolean;\n}\n\n/**\n * Sentry plugin implementation\n */\n/**\n * Sentry plugin implementation.\n *\n * Integrates Sentry error tracking and performance monitoring into the observability system.\n * Auto-detects the appropriate Sentry package (@sentry/node, @sentry/browser, @sentry/nextjs)\n * based on the runtime environment.\n */\nexport class SentryPlugin<\n T extends SentryClient = SentryClient,\n> implements ObservabilityServerPlugin<T> {\n name = 'sentry';\n enabled: boolean;\n protected client: T | undefined;\n protected initialized = false;\n protected sentryPackage: string;\n protected config: SentryPluginConfig;\n\n /**\n * Create a new SentryPlugin instance.\n *\n * @param config - Sentry plugin configuration\n */\n constructor(config: SentryPluginConfig = {}) {\n this.config = config;\n const env = safeEnv();\n // Auto-enable if DSN is provided\n const hasDSN = config.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;\n this.enabled = config.enabled ?? Boolean(hasDSN);\n\n // Determine Sentry package to use\n this.sentryPackage = config.sentryPackage ?? this.detectSentryPackage();\n }\n\n /**\n * Detect which Sentry package to use based on the runtime environment.\n *\n * @returns Package name ('@sentry/node', '@sentry/browser', or '@sentry/nextjs')\n */\n private detectSentryPackage(): string {\n if (isBrowser()) {\n return '@sentry/browser';\n } else if (process.env.NEXT_RUNTIME === 'edge') {\n return '@sentry/nextjs'; // Next.js edge uses same package\n } else if (process.env.NEXT_RUNTIME) {\n return '@sentry/nextjs';\n } else {\n return '@sentry/node';\n }\n }\n\n getClient(): T | undefined {\n return this.client;\n }\n\n /**\n * Get safe environment access (for testing/mocking).\n *\n * @returns Environment configuration object\n */\n protected getSafeEnv() {\n return safeEnv();\n }\n\n async initialize(config?: SentryPluginConfig): Promise<void> {\n if (this.initialized || !this.enabled) return;\n\n const env = safeEnv();\n const mergedConfig = { ...this.config, ...config };\n\n // Check for DSN\n const dsn = mergedConfig.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;\n if (!dsn) {\n logWarn('Sentry plugin: No DSN provided, skipping initialization');\n this.enabled = false;\n return;\n }\n\n try {\n // Dynamic import of the specified Sentry package\n this.client = (await import(/* webpackIgnore: true */ this.sentryPackage)) as T;\n\n if (this.client && this.enabled) {\n // Build integrations array if not provided\n let { integrations } = mergedConfig;\n if (!integrations && this.client.browserTracingIntegration) {\n integrations = [];\n\n // Add browser tracing for performance monitoring\n if (\n mergedConfig.tracesSampleRate !== undefined ||\n env.SENTRY_TRACES_SAMPLE_RATE !== undefined\n ) {\n integrations.push(this.client.browserTracingIntegration());\n }\n\n // Add replay integration if configured\n if (\n this.client.replayIntegration &&\n (mergedConfig.replaysSessionSampleRate !== undefined ||\n env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE !== undefined)\n ) {\n integrations.push(this.client.replayIntegration());\n }\n\n // Add profiling if configured\n if (\n this.client.profilesIntegration &&\n (mergedConfig.profilesSampleRate !== undefined ||\n env.SENTRY_PROFILES_SAMPLE_RATE !== undefined)\n ) {\n integrations.push(this.client.profilesIntegration());\n }\n }\n\n // Add console logging integration if logs are enabled\n const enableLogs = mergedConfig.enableLogs ?? true;\n if (enableLogs && this.client.consoleLoggingIntegration) {\n const consoleLoggingConfig = mergedConfig.consoleLoggingIntegration || {\n levels: ['log', 'warn', 'error'],\n };\n if (!integrations) {\n integrations = [];\n }\n integrations.push(this.client.consoleLoggingIntegration(consoleLoggingConfig));\n }\n\n this.client.init({\n dsn,\n environment: mergedConfig.environment ?? env.SENTRY_ENVIRONMENT ?? process.env.NODE_ENV,\n release: mergedConfig.release ?? env.SENTRY_RELEASE,\n debug: mergedConfig.debug ?? env.SENTRY_DEBUG,\n\n // Enable logs to be sent to Sentry\n enableLogs,\n\n // Sampling rates\n tracesSampleRate: mergedConfig.tracesSampleRate ?? env.SENTRY_TRACES_SAMPLE_RATE,\n profilesSampleRate: mergedConfig.profilesSampleRate ?? env.SENTRY_PROFILES_SAMPLE_RATE,\n replaysSessionSampleRate:\n mergedConfig.replaysSessionSampleRate ?? env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE,\n replaysOnErrorSampleRate:\n mergedConfig.replaysOnErrorSampleRate ?? env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE,\n\n // Integrations and hooks\n integrations,\n beforeSend: mergedConfig.beforeSend,\n beforeSendTransaction: mergedConfig.beforeSendTransaction,\n // Use provided beforeSendLog, or default filter if logs are enabled and no custom filter provided\n beforeSendLog:\n mergedConfig.beforeSendLog ||\n (enableLogs ? (log: any) => defaultBeforeSendLog(log, !isBrowser()) : undefined),\n\n // Other options\n tracePropagationTargets: mergedConfig.tracePropagationTargets,\n initialScope: mergedConfig.initialScope,\n maxBreadcrumbs: mergedConfig.maxBreadcrumbs,\n attachStacktrace: mergedConfig.attachStacktrace,\n autoSessionTracking: mergedConfig.autoSessionTracking,\n });\n\n this.initialized = true;\n }\n } catch (error) {\n logError(`Failed to import Sentry package '${this.sentryPackage}'`, { error });\n this.enabled = false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.client && this.initialized) {\n // Use close if available, otherwise flush\n if (this.client.close) {\n await this.client.close();\n } else if (this.client.flush) {\n await this.client.flush();\n }\n this.initialized = false;\n }\n }\n\n /**\n * Clean up the plugin (alias for shutdown)\n */\n async cleanup(): Promise<void> {\n await this.shutdown();\n }\n\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Additional build-time guard to prevent errors during static generation\n if (typeof this.client.captureException !== 'function') {\n // During build/static generation, Sentry client may not be properly initialized\n // Fall back to logging in development\n if (process.env.NODE_ENV === 'development') {\n logError('[Sentry Fallback] Exception', { error });\n }\n return;\n }\n\n try {\n this.client.captureException(error, context);\n } catch (captureError) {\n // Graceful fallback if Sentry fails during build\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to capture exception', { error: captureError });\n logError('[Sentry Fallback] Exception', { error });\n }\n }\n }\n\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Prefer Sentry.logger if available (structured logs)\n if (this.client.logger) {\n try {\n const attributes: Record<string, unknown> | undefined = context\n ? ((context.extra as Record<string, unknown> | undefined) ??\n (context as Record<string, unknown>))\n : undefined;\n switch (level) {\n case 'debug':\n this.client.logger.debug(message, attributes);\n return;\n case 'info':\n this.client.logger.info(message, attributes);\n return;\n case 'warning':\n this.client.logger.warn(message, attributes);\n return;\n case 'error':\n this.client.logger.error(message, attributes);\n return;\n }\n } catch (error) {\n // Fall through to captureMessage if logger fails\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log via logger', { error });\n }\n }\n }\n\n // Fallback to captureMessage for compatibility\n // Additional build-time guard to prevent errors during static generation\n if (typeof this.client.captureMessage !== 'function') {\n // During build/static generation, Sentry client may not be properly initialized\n // Fall back to logging in development\n if (process.env.NODE_ENV === 'development') {\n if (level === 'error') {\n logError(`[Sentry Fallback] ${message}`);\n } else if (level === 'warning') {\n logWarn(`[Sentry Fallback] ${message}`);\n } else {\n logDebug(`[Sentry Fallback] ${message}`);\n }\n }\n return;\n }\n\n // Map our log levels to Sentry severity levels\n const sentryLevel =\n level === 'warning'\n ? 'warning'\n : level === 'error'\n ? 'error'\n : level === 'debug'\n ? 'debug'\n : 'info';\n\n try {\n // Build capture context from ObservabilityContext\n const captureContext = context\n ? {\n level: sentryLevel,\n extra: context.extra ?? context,\n tags: context.tags,\n }\n : sentryLevel;\n\n this.client.captureMessage(message, captureContext);\n } catch (error) {\n // Graceful fallback if Sentry fails during build\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to capture message', { error });\n if (level === 'error') {\n logError(`[Sentry Fallback] ${message}`);\n } else if (level === 'warning') {\n logWarn(`[Sentry Fallback] ${message}`);\n } else {\n logDebug(`[Sentry Fallback] ${message}`);\n }\n }\n }\n }\n\n setUser(user: ObservabilityUser | null): void {\n if (!this.enabled || !this.client) return;\n this.client.setUser(user);\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n if (!this.enabled || !this.client) return;\n this.client.addBreadcrumb({\n ...breadcrumb,\n timestamp: breadcrumb.timestamp ?? Date.now() / 1000,\n });\n }\n\n withScope(callback: (scope: any) => void): void {\n if (!this.enabled || !this.client) return;\n this.client.withScope(callback);\n }\n\n /**\n * Start a new transaction\n */\n startTransaction(\n context: TransactionContext,\n customSamplingContext?: any,\n ): Transaction | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.startTransaction) {\n return this.client.startTransaction(context, customSamplingContext);\n }\n\n // Fallback for older versions\n logWarn('startTransaction not available in this Sentry version');\n return undefined;\n }\n\n /**\n * Start a new span\n */\n startSpan(context: SpanContext): Span | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.startSpan) {\n return this.client.startSpan(context);\n }\n\n // Try to create span from active transaction\n const transaction = this.getActiveTransaction();\n if (transaction?.startChild) {\n return transaction.startChild(context);\n }\n\n return undefined;\n }\n\n /**\n * Get the currently active transaction\n */\n getActiveTransaction(): Transaction | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.getActiveTransaction) {\n return this.client.getActiveTransaction();\n }\n\n // Try to get from current scope\n if (this.client.getCurrentScope) {\n const scope = this.client.getCurrentScope();\n if (scope?.getTransaction) {\n return scope.getTransaction();\n }\n }\n\n return undefined;\n }\n\n /**\n * Configure the current scope\n */\n configureScope(callback: (scope: Scope) => void): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.configureScope) {\n this.client.configureScope(callback);\n } else if (this.client.withScope) {\n // Fallback using withScope\n this.client.withScope(callback);\n }\n }\n\n /**\n * Get the current hub instance\n */\n getCurrentHub(): Hub | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.getCurrentHub) {\n return this.client.getCurrentHub();\n }\n\n return undefined;\n }\n\n /**\n * Set a measurement on the active transaction\n */\n setMeasurement(name: string, value: number, unit?: string): void {\n if (!this.enabled || !this.client) return;\n\n const transaction = this.getActiveTransaction();\n if (transaction?.setMeasurement) {\n transaction.setMeasurement(name, value, unit);\n }\n }\n\n /**\n * Add performance entries as breadcrumbs and measurements\n */\n addPerformanceEntries(\n entries: Array<{\n entryType: string;\n name: string;\n startTime: number;\n duration: number;\n [key: string]: unknown;\n }>,\n ): void {\n if (!this.enabled || !this.client) return;\n\n const transaction = this.getActiveTransaction();\n\n entries.forEach(entry => {\n // Add as breadcrumb for context\n this.addBreadcrumb({\n category: 'performance',\n message: `${entry.entryType}: ${entry.name}`,\n data: {\n name: entry.name,\n duration: entry.duration,\n startTime: entry.startTime,\n ...(entry.entryType === 'navigation' && {\n transferSize: (entry as { transferSize?: number }).transferSize,\n encodedBodySize: (entry as { encodedBodySize?: number }).encodedBodySize,\n decodedBodySize: (entry as { decodedBodySize?: number }).decodedBodySize,\n }),\n ...(entry.entryType === 'resource' && {\n initiatorType: (entry as { initiatorType?: string }).initiatorType,\n transferSize: (entry as { transferSize?: number }).transferSize,\n }),\n },\n });\n\n // Add measurements for key metrics\n if (transaction && entry.entryType === 'navigation') {\n const navEntry = entry as unknown as {\n responseStart?: number;\n fetchStart?: number;\n domInteractive?: number;\n domComplete?: number;\n loadEventEnd?: number;\n transferSize?: number;\n encodedBodySize?: number;\n decodedBodySize?: number;\n [key: string]: unknown;\n };\n\n // Core Web Vitals and other metrics\n const fetchStart = navEntry.fetchStart ?? 0;\n if (navEntry.responseStart !== undefined) {\n this.setMeasurement('fcp', navEntry.responseStart - fetchStart, 'millisecond');\n }\n if (navEntry.domInteractive !== undefined) {\n this.setMeasurement(\n 'dom_interactive',\n navEntry.domInteractive - fetchStart,\n 'millisecond',\n );\n }\n if (navEntry.domComplete !== undefined) {\n this.setMeasurement('dom_complete', navEntry.domComplete - fetchStart, 'millisecond');\n }\n if (navEntry.loadEventEnd !== undefined) {\n this.setMeasurement('load_event_end', navEntry.loadEventEnd - fetchStart, 'millisecond');\n }\n }\n });\n }\n\n /**\n * Record a Web Vital measurement\n */\n recordWebVital(\n name: 'FCP' | 'LCP' | 'FID' | 'CLS' | 'TTFB' | 'INP' | string,\n value: number,\n options?: {\n unit?: string;\n rating?: 'good' | 'needs-improvement' | 'poor';\n },\n ): void {\n if (!this.enabled || !this.client) return;\n\n const { unit = 'millisecond', rating } = options ?? {};\n const transaction = this.getActiveTransaction();\n\n if (transaction) {\n // Set the measurement\n transaction.setMeasurement(name.toLowerCase(), value, unit);\n\n // Add rating as tag if provided\n if (rating) {\n transaction.setTag(`webvital.${name.toLowerCase()}.rating`, rating);\n }\n\n // Also send as a standalone event for monitoring\n this.client.captureMessage(`Web Vital: ${name}`, {\n level: 'info',\n tags: {\n 'webvital.name': name,\n 'webvital.value': value,\n 'webvital.unit': unit,\n ...(rating && { 'webvital.rating': rating }),\n },\n contexts: {\n trace: {\n trace_id: transaction.traceId,\n span_id: transaction.spanId,\n },\n },\n });\n }\n }\n\n /**\n * Create a custom performance mark\n */\n mark(name: string, options?: { detail?: any }): void {\n if (!this.enabled) return;\n\n // Use Performance API if available\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(name, options);\n }\n\n // Also add as breadcrumb\n this.addBreadcrumb({\n category: 'performance.mark',\n message: name,\n data: options?.detail,\n timestamp: Date.now() / 1000,\n });\n }\n\n /**\n * Create a custom performance measure\n */\n measure(\n name: string,\n startMarkOrOptions?:\n | string\n | { start?: string; end?: string; duration?: number; detail?: unknown },\n endMark?: string,\n ): void {\n if (!this.enabled) return;\n\n // Use Performance API if available\n if (typeof performance !== 'undefined' && performance.measure) {\n if (typeof startMarkOrOptions === 'string') {\n performance.measure(name, startMarkOrOptions, endMark);\n } else if (startMarkOrOptions) {\n performance.measure(name, startMarkOrOptions);\n } else {\n // No options provided, create a simple measure\n performance.measure(name);\n }\n\n // Get the measure to record its duration\n const measures = performance.getEntriesByName(name, 'measure');\n const measure = measures[measures.length - 1];\n\n if (measure) {\n this.setMeasurement(name, measure.duration, 'millisecond');\n\n this.addBreadcrumb({\n category: 'performance.measure',\n message: name,\n data: {\n duration: measure.duration,\n startTime: measure.startTime,\n },\n timestamp: measure.startTime / 1000,\n });\n }\n }\n }\n\n /**\n * Log a trace message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Trace message to log\n * @param attributes - Optional attributes to include with the log\n */\n logTrace(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.trace) {\n try {\n this.client.logger.trace(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log trace', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'debug', attributes);\n }\n\n /**\n * Log a debug message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Debug message to log\n * @param attributes - Optional attributes to include with the log\n */\n logDebug(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.debug) {\n try {\n this.client.logger.debug(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log debug', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'debug', attributes);\n }\n\n /**\n * Log an info message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Info message to log\n * @param attributes - Optional attributes to include with the log\n */\n logInfo(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.info) {\n try {\n this.client.logger.info(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log info', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'info', attributes);\n }\n\n /**\n * Log a warning message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Warning message to log\n * @param attributes - Optional attributes to include with the log\n */\n logWarn(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.warn) {\n try {\n this.client.logger.warn(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log warn', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'warning', attributes);\n }\n\n /**\n * Log an error message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Error message to log\n * @param attributes - Optional attributes to include with the log\n */\n logError(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.error) {\n try {\n this.client.logger.error(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log error', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'error', attributes);\n }\n\n /**\n * Log a fatal message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Fatal message to log\n * @param attributes - Optional attributes to include with the log\n */\n logFatal(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.fatal) {\n try {\n this.client.logger.fatal(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log fatal', { error });\n }\n }\n }\n\n // Fallback to captureMessage with error level\n this.captureMessage(message, 'error', attributes);\n }\n\n /**\n * Get the Sentry.logger instance if available.\n * This allows direct access to Sentry.logger APIs including fmt.\n *\n * @returns Sentry.logger instance or undefined if not available\n *\n * @example\n * ```typescript\n * const logger = sentryPlugin.getLogger();\n * if (logger) {\n * logger.info(logger.fmt`User ${user.id} logged in`);\n * }\n * ```\n */\n getLogger(): SentryClient['logger'] | undefined {\n if (!this.enabled || !this.client) return undefined;\n return this.client.logger;\n }\n\n async flush(timeout?: number): Promise<boolean> {\n if (!this.enabled || !this.client || !this.client.flush) return true;\n try {\n return await this.client.flush(timeout);\n } catch (_error) {\n return false;\n }\n }\n}\n\n/**\n * Factory function to create a Sentry plugin.\n *\n * Creates a configured SentryPlugin instance with optional configuration.\n * Auto-detects the appropriate Sentry package based on the environment.\n *\n * @param config - Optional Sentry plugin configuration\n * @returns SentryPlugin instance\n *\n * @example\n * ```typescript\n * const sentry = createSentryPlugin({\n * dsn: 'https://...',\n * environment: 'production',\n * tracesSampleRate: 0.1,\n * });\n * ```\n */\nexport const createSentryPlugin = <T extends SentryClient = SentryClient>(\n config?: SentryPluginConfig,\n): SentryPlugin<T> => {\n return new SentryPlugin<T>(config);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { a as Breadcrumb, f as ObservabilityUser, l as ObservabilityContext, n as ObservabilityServerPlugin, o as LogLevel } from "./plugin-Bfq-o3nr.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/betterstack/plugin.d.ts
|
|
4
|
+
interface LogtailClient {
|
|
5
|
+
info(message: string, data?: any): void;
|
|
6
|
+
warn(message: string, data?: any): void;
|
|
7
|
+
error(message: string, data?: any): void;
|
|
8
|
+
debug(message: string, data?: any): void;
|
|
9
|
+
flush(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
interface BetterStackPluginConfig {
|
|
12
|
+
logtailPackage?: string;
|
|
13
|
+
sourceToken?: string;
|
|
14
|
+
endpoint?: string;
|
|
15
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'off';
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
batchInterval?: number;
|
|
18
|
+
batchSize?: number;
|
|
19
|
+
retryCount?: number;
|
|
20
|
+
retryBackoff?: boolean;
|
|
21
|
+
middleware?: any[];
|
|
22
|
+
}
|
|
23
|
+
declare class BetterStackPlugin<T extends LogtailClient = LogtailClient> implements ObservabilityServerPlugin<T> {
|
|
24
|
+
name: string;
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
protected client: T | undefined;
|
|
27
|
+
protected initialized: boolean;
|
|
28
|
+
protected logtailPackage: string;
|
|
29
|
+
protected currentUser: ObservabilityUser | null;
|
|
30
|
+
protected breadcrumbs: Breadcrumb[];
|
|
31
|
+
protected breadcrumbIndex: number;
|
|
32
|
+
protected config: BetterStackPluginConfig;
|
|
33
|
+
constructor(config?: BetterStackPluginConfig);
|
|
34
|
+
private detectLogtailPackage;
|
|
35
|
+
getClient(): T | undefined;
|
|
36
|
+
protected getSafeEnv(): Readonly<{
|
|
37
|
+
LOGTAIL_SOURCE_TOKEN?: string | undefined;
|
|
38
|
+
BETTERSTACK_SOURCE_TOKEN?: string | undefined;
|
|
39
|
+
BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
40
|
+
BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
41
|
+
BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
42
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN?: string | undefined;
|
|
43
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN?: string | undefined;
|
|
44
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
45
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
46
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
initialize(config?: BetterStackPluginConfig): Promise<void>;
|
|
49
|
+
shutdown(): Promise<void>;
|
|
50
|
+
captureException(error: Error | unknown, context?: ObservabilityContext): void;
|
|
51
|
+
captureMessage(message: string, level?: LogLevel, context?: ObservabilityContext): void;
|
|
52
|
+
setUser(user: ObservabilityUser | null): void;
|
|
53
|
+
addBreadcrumb(breadcrumb: Breadcrumb): void;
|
|
54
|
+
private getRecentBreadcrumbs;
|
|
55
|
+
withScope(callback: (scope: any) => void): void;
|
|
56
|
+
flush(_timeout?: number): Promise<boolean>;
|
|
57
|
+
}
|
|
58
|
+
declare const createBetterStackPlugin: <T extends LogtailClient = LogtailClient>(config?: BetterStackPluginConfig) => BetterStackPlugin<T>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { BetterStackPluginConfig as n, createBetterStackPlugin as r, BetterStackPlugin as t };
|
|
61
|
+
//# sourceMappingURL=plugin-CaQxviDs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-CaQxviDs.d.mts","names":[],"sources":["../src/plugins/betterstack/plugin.ts"],"mappings":";;;UA+BU,aAAA;EACR,IAAA,CAAK,OAAA,UAAiB,IAAA;EACtB,IAAA,CAAK,OAAA,UAAiB,IAAA;EACtB,KAAA,CAAM,OAAA,UAAiB,IAAA;EACvB,KAAA,CAAM,OAAA,UAAiB,IAAA;EACvB,KAAA,IAAS,OAAA;AAAA;AAAA,UAMM,uBAAA;EAKf,cAAA;EAGA,WAAA;EACA,QAAA;EACA,QAAA;EACA,OAAA;EAGA,aAAA;EACA,SAAA;EACA,UAAA;EACA,YAAA;EACA,UAAA;AAAA;AAAA,cAaW,iBAAA,WACD,aAAA,GAAgB,aAAA,aACf,yBAAA,CAA0B,CAAA;EACrC,IAAA;EACA,OAAA;EAAA,UACU,MAAA,EAAQ,CAAA;EAAA,UACR,WAAA;EAAA,UACA,cAAA;EAAA,UACA,WAAA,EAAa,iBAAA;EAAA,UACb,WAAA,EAAa,UAAA;EAAA,UACb,eAAA;EAAA,UACA,MAAA,EAAQ,uBAAA;cAON,MAAA,GAAQ,uBAAA;EAAA,QAuBZ,oBAAA;EASR,SAAA,CAAA,GAAa,CAAA;EAAA,UASH,UAAA,CAAA,GAAU,QAAA;;;;;;;;;;;;EAId,UAAA,CAAW,MAAA,GAAS,uBAAA,GAA0B,OAAA;EAmE9C,QAAA,CAAA,GAAY,OAAA;EAOlB,gBAAA,CAAiB,KAAA,EAAO,KAAA,YAAiB,OAAA,GAAU,oBAAA;EAqBnD,cAAA,CAAe,OAAA,UAAiB,KAAA,GAAO,QAAA,EAAmB,OAAA,GAAU,oBAAA;EA8BpE,OAAA,CAAQ,IAAA,EAAM,iBAAA;EAKd,aAAA,CAAc,UAAA,EAAY,UAAA;EAAA,QAuBlB,oBAAA;EA8BR,SAAA,CAAU,QAAA,GAAW,KAAA;EAmBf,KAAA,CAAM,QAAA,YAAoB,OAAA;AAAA;AAAA,cA8BrB,uBAAA,aAAqC,aAAA,GAAgB,aAAA,EAChE,MAAA,GAAS,uBAAA,KACR,iBAAA,CAAkB,CAAA"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { safeEnv } from "./plugins-betterstack-env.mjs";
|
|
2
|
+
import { logError, logWarn } from "@od-oneapp/shared/logger";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/betterstack/plugin.ts
|
|
5
|
+
/**
|
|
6
|
+
* @fileoverview Better Stack (Logtail) plugin implementation
|
|
7
|
+
* Better Stack (Logtail) plugin implementation
|
|
8
|
+
* Updated to use official @logtail packages
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Maximum number of breadcrumbs to include in error/message context
|
|
12
|
+
* Limits context size to prevent excessive data transmission
|
|
13
|
+
*/
|
|
14
|
+
const MAX_BREADCRUMBS_IN_CONTEXT = 10;
|
|
15
|
+
/**
|
|
16
|
+
* Maximum number of breadcrumbs to store in memory
|
|
17
|
+
* Prevents unbounded memory growth while maintaining useful history
|
|
18
|
+
*/
|
|
19
|
+
const MAX_BREADCRUMBS_STORED = 100;
|
|
20
|
+
/**
|
|
21
|
+
* Better Stack plugin implementation using official @logtail packages
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Better Stack (Logtail) plugin implementation.
|
|
25
|
+
*
|
|
26
|
+
* Integrates Better Stack logging service into the observability system.
|
|
27
|
+
* Uses official @logtail packages (@logtail/js or @logtail/next) for unified
|
|
28
|
+
* logging across environments.
|
|
29
|
+
*/
|
|
30
|
+
var BetterStackPlugin = class {
|
|
31
|
+
name = "betterstack";
|
|
32
|
+
enabled;
|
|
33
|
+
client;
|
|
34
|
+
initialized = false;
|
|
35
|
+
logtailPackage;
|
|
36
|
+
currentUser = null;
|
|
37
|
+
breadcrumbs = [];
|
|
38
|
+
breadcrumbIndex = 0;
|
|
39
|
+
config;
|
|
40
|
+
/**
|
|
41
|
+
* Create a new BetterStackPlugin instance.
|
|
42
|
+
*
|
|
43
|
+
* @param config - Better Stack plugin configuration
|
|
44
|
+
*/
|
|
45
|
+
constructor(config = {}) {
|
|
46
|
+
this.config = config;
|
|
47
|
+
const env = safeEnv();
|
|
48
|
+
const hasToken = config.sourceToken ?? env.BETTER_STACK_SOURCE_TOKEN ?? env.BETTERSTACK_SOURCE_TOKEN ?? env.LOGTAIL_SOURCE_TOKEN ?? env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ?? env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? env.NEXT_PUBLIC_LOGTAIL_TOKEN;
|
|
49
|
+
this.enabled = config.enabled ?? Boolean(hasToken);
|
|
50
|
+
this.logtailPackage = config.logtailPackage ?? this.detectLogtailPackage();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Detect which Logtail package to use based on the runtime environment.
|
|
54
|
+
*
|
|
55
|
+
* @returns Package name ('@logtail/next' for Next.js, '@logtail/js' otherwise)
|
|
56
|
+
*/
|
|
57
|
+
detectLogtailPackage() {
|
|
58
|
+
if (process.env.NEXT_RUNTIME) return "@logtail/next";
|
|
59
|
+
return "@logtail/js";
|
|
60
|
+
}
|
|
61
|
+
getClient() {
|
|
62
|
+
return this.client;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get safe environment access (for testing/mocking).
|
|
66
|
+
*
|
|
67
|
+
* @returns Environment configuration object
|
|
68
|
+
*/
|
|
69
|
+
getSafeEnv() {
|
|
70
|
+
return safeEnv();
|
|
71
|
+
}
|
|
72
|
+
async initialize(config) {
|
|
73
|
+
if (this.initialized || !this.enabled) return;
|
|
74
|
+
const env = safeEnv();
|
|
75
|
+
const mergedConfig = {
|
|
76
|
+
...this.config,
|
|
77
|
+
...config
|
|
78
|
+
};
|
|
79
|
+
const sourceToken = mergedConfig.sourceToken ?? env.BETTER_STACK_SOURCE_TOKEN ?? env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ?? env.LOGTAIL_SOURCE_TOKEN ?? env.BETTERSTACK_SOURCE_TOKEN ?? env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? env.NEXT_PUBLIC_BETTERSTACK_TOKEN;
|
|
80
|
+
if (!sourceToken) {
|
|
81
|
+
logWarn("Better Stack plugin: No source token provided, skipping initialization");
|
|
82
|
+
this.enabled = false;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const LogtailModule = await import(
|
|
87
|
+
/* webpackIgnore: true */
|
|
88
|
+
this.logtailPackage
|
|
89
|
+
);
|
|
90
|
+
const LogtailClass = LogtailModule.default ?? LogtailModule.Logtail ?? LogtailModule;
|
|
91
|
+
if (!LogtailClass) {
|
|
92
|
+
logError(`Better Stack plugin: Could not find Logtail class in ${this.logtailPackage}`, { logtailPackage: this.logtailPackage });
|
|
93
|
+
this.enabled = false;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const logtailConfig = { sourceToken };
|
|
97
|
+
if (mergedConfig.endpoint ?? env.BETTER_STACK_INGESTING_URL ?? env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL) logtailConfig.endpoint = mergedConfig.endpoint ?? env.BETTER_STACK_INGESTING_URL ?? env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL;
|
|
98
|
+
this.client = new LogtailClass(logtailConfig);
|
|
99
|
+
this.initialized = true;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logError(`Failed to import Logtail package '${this.logtailPackage}'`, {
|
|
102
|
+
error,
|
|
103
|
+
logtailPackage: this.logtailPackage
|
|
104
|
+
});
|
|
105
|
+
this.enabled = false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async shutdown() {
|
|
109
|
+
if (this.client && this.initialized) {
|
|
110
|
+
await this.client.flush();
|
|
111
|
+
this.initialized = false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
captureException(error, context) {
|
|
115
|
+
if (!this.enabled || !this.client) return;
|
|
116
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
117
|
+
const data = {
|
|
118
|
+
error: {
|
|
119
|
+
name: errorObj.name,
|
|
120
|
+
message: errorObj.message,
|
|
121
|
+
stack: errorObj.stack
|
|
122
|
+
},
|
|
123
|
+
context: context?.extra,
|
|
124
|
+
tags: context?.tags,
|
|
125
|
+
user: context?.user ?? this.currentUser,
|
|
126
|
+
breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT)
|
|
127
|
+
};
|
|
128
|
+
this.client.error(errorObj.message, data);
|
|
129
|
+
}
|
|
130
|
+
captureMessage(message, level = "info", context) {
|
|
131
|
+
if (!this.enabled || !this.client) return;
|
|
132
|
+
const data = {
|
|
133
|
+
level,
|
|
134
|
+
context: context?.extra,
|
|
135
|
+
tags: context?.tags,
|
|
136
|
+
user: context?.user ?? this.currentUser,
|
|
137
|
+
breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT)
|
|
138
|
+
};
|
|
139
|
+
switch (level) {
|
|
140
|
+
case "debug":
|
|
141
|
+
this.client.debug(message, data);
|
|
142
|
+
break;
|
|
143
|
+
case "warning":
|
|
144
|
+
this.client.warn(message, data);
|
|
145
|
+
break;
|
|
146
|
+
case "error":
|
|
147
|
+
this.client.error(message, data);
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
this.client.info(message, data);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
setUser(user) {
|
|
155
|
+
if (!this.enabled) return;
|
|
156
|
+
this.currentUser = user;
|
|
157
|
+
}
|
|
158
|
+
addBreadcrumb(breadcrumb) {
|
|
159
|
+
if (!this.enabled) return;
|
|
160
|
+
const enriched = {
|
|
161
|
+
...breadcrumb,
|
|
162
|
+
timestamp: breadcrumb.timestamp ?? Date.now() / 1e3
|
|
163
|
+
};
|
|
164
|
+
if (this.breadcrumbs.length < MAX_BREADCRUMBS_STORED) this.breadcrumbs.push(enriched);
|
|
165
|
+
else {
|
|
166
|
+
this.breadcrumbs[this.breadcrumbIndex] = enriched;
|
|
167
|
+
this.breadcrumbIndex = (this.breadcrumbIndex + 1) % MAX_BREADCRUMBS_STORED;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get the most recent breadcrumbs in chronological order
|
|
172
|
+
* @param count - Number of breadcrumbs to retrieve
|
|
173
|
+
* @returns Array of recent breadcrumbs
|
|
174
|
+
*/
|
|
175
|
+
getRecentBreadcrumbs(count) {
|
|
176
|
+
const { length } = this.breadcrumbs;
|
|
177
|
+
if (length === 0) return [];
|
|
178
|
+
if (length <= count) return this.breadcrumbs.slice();
|
|
179
|
+
if (length < MAX_BREADCRUMBS_STORED) return this.breadcrumbs.slice(length - count);
|
|
180
|
+
const result = [];
|
|
181
|
+
const start = (this.breadcrumbIndex - count + length) % length;
|
|
182
|
+
for (let i = 0; i < count; i++) {
|
|
183
|
+
const index = (start + i) % length;
|
|
184
|
+
const breadcrumb = this.breadcrumbs[index];
|
|
185
|
+
if (breadcrumb) result.push(breadcrumb);
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
withScope(callback) {
|
|
190
|
+
if (!this.enabled) return;
|
|
191
|
+
try {
|
|
192
|
+
callback({
|
|
193
|
+
setContext: (_key, _context) => {},
|
|
194
|
+
setUser: (user) => {
|
|
195
|
+
this.setUser(user);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
} catch {}
|
|
199
|
+
}
|
|
200
|
+
async flush(_timeout) {
|
|
201
|
+
if (!this.enabled || !this.client) return true;
|
|
202
|
+
try {
|
|
203
|
+
await this.client.flush();
|
|
204
|
+
return true;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
logError("Better Stack flush error", { error });
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Factory function to create a Better Stack plugin.
|
|
213
|
+
*
|
|
214
|
+
* Creates a configured BetterStackPlugin instance with optional configuration.
|
|
215
|
+
* Auto-detects the appropriate @logtail package based on the environment.
|
|
216
|
+
*
|
|
217
|
+
* @param config - Optional Better Stack plugin configuration
|
|
218
|
+
* @returns BetterStackPlugin instance
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const betterstack = createBetterStackPlugin({
|
|
223
|
+
* sourceToken: '...',
|
|
224
|
+
* logLevel: 'info',
|
|
225
|
+
* });
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
const createBetterStackPlugin = (config) => {
|
|
229
|
+
return new BetterStackPlugin(config);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
//#endregion
|
|
233
|
+
export { createBetterStackPlugin as n, BetterStackPlugin as t };
|
|
234
|
+
//# sourceMappingURL=plugin-lPdJirTY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-lPdJirTY.mjs","names":[],"sources":["../src/plugins/betterstack/plugin.ts"],"sourcesContent":["/**\n * @fileoverview Better Stack (Logtail) plugin implementation\n * Better Stack (Logtail) plugin implementation\n * Updated to use official @logtail packages\n */\n\nimport { logError, logWarn } from '@repo/shared/logger';\nimport type { ObservabilityServerPlugin } from '../../core/plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityUser,\n} from '../../core/types';\nimport { safeEnv } from './env';\n\n/**\n * Maximum number of breadcrumbs to include in error/message context\n * Limits context size to prevent excessive data transmission\n */\nconst MAX_BREADCRUMBS_IN_CONTEXT = 10;\n\n/**\n * Maximum number of breadcrumbs to store in memory\n * Prevents unbounded memory growth while maintaining useful history\n */\nconst MAX_BREADCRUMBS_STORED = 100;\n\n/**\n * Minimal Logtail interface for common methods across all @logtail packages\n */\ninterface LogtailClient {\n info(message: string, data?: any): void;\n warn(message: string, data?: any): void;\n error(message: string, data?: any): void;\n debug(message: string, data?: any): void;\n flush(): Promise<void>;\n}\n\n/**\n * Better Stack plugin configuration\n */\nexport interface BetterStackPluginConfig {\n /**\n * The @logtail package to use (e.g., '@logtail/js', '@logtail/next')\n * If not provided, the plugin will auto-detect based on environment\n */\n logtailPackage?: string;\n\n // Core configuration options\n sourceToken?: string;\n endpoint?: string;\n logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'off';\n enabled?: boolean;\n\n // Advanced options\n batchInterval?: number;\n batchSize?: number;\n retryCount?: number;\n retryBackoff?: boolean;\n middleware?: any[];\n}\n\n/**\n * Better Stack plugin implementation using official @logtail packages\n */\n/**\n * Better Stack (Logtail) plugin implementation.\n *\n * Integrates Better Stack logging service into the observability system.\n * Uses official @logtail packages (@logtail/js or @logtail/next) for unified\n * logging across environments.\n */\nexport class BetterStackPlugin<\n T extends LogtailClient = LogtailClient,\n> implements ObservabilityServerPlugin<T> {\n name = 'betterstack';\n enabled: boolean;\n protected client: T | undefined;\n protected initialized = false;\n protected logtailPackage: string;\n protected currentUser: ObservabilityUser | null = null;\n protected breadcrumbs: Breadcrumb[] = [];\n protected breadcrumbIndex = 0;\n protected config: BetterStackPluginConfig;\n\n /**\n * Create a new BetterStackPlugin instance.\n *\n * @param config - Better Stack plugin configuration\n */\n constructor(config: BetterStackPluginConfig = {}) {\n this.config = config;\n const env = safeEnv();\n // Auto-enable if token is provided\n const hasToken =\n config.sourceToken ??\n env.BETTER_STACK_SOURCE_TOKEN ??\n env.BETTERSTACK_SOURCE_TOKEN ??\n env.LOGTAIL_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTERSTACK_TOKEN ??\n env.NEXT_PUBLIC_LOGTAIL_TOKEN;\n this.enabled = config.enabled ?? Boolean(hasToken);\n\n // Determine Logtail package to use\n this.logtailPackage = config.logtailPackage ?? this.detectLogtailPackage();\n }\n\n /**\n * Detect which Logtail package to use based on the runtime environment.\n *\n * @returns Package name ('@logtail/next' for Next.js, '@logtail/js' otherwise)\n */\n private detectLogtailPackage(): string {\n // Next.js environments use Next.js package\n if (process.env.NEXT_RUNTIME) {\n return '@logtail/next';\n }\n // All other environments use the unified js package (bundles both node and browser)\n return '@logtail/js';\n }\n\n getClient(): T | undefined {\n return this.client;\n }\n\n /**\n * Get safe environment access (for testing/mocking).\n *\n * @returns Environment configuration object\n */\n protected getSafeEnv() {\n return safeEnv();\n }\n\n async initialize(config?: BetterStackPluginConfig): Promise<void> {\n if (this.initialized || !this.enabled) return;\n\n const env = safeEnv();\n const mergedConfig = { ...this.config, ...config };\n\n // Get source token with priority: config > new env vars > legacy env vars\n const sourceToken =\n mergedConfig.sourceToken ??\n env.BETTER_STACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n env.LOGTAIL_SOURCE_TOKEN ??\n env.BETTERSTACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_LOGTAIL_TOKEN ??\n env.NEXT_PUBLIC_BETTERSTACK_TOKEN;\n\n if (!sourceToken) {\n logWarn('Better Stack plugin: No source token provided, skipping initialization');\n this.enabled = false;\n return;\n }\n\n try {\n // Dynamic import of the specified Logtail package\n const LogtailModule = await import(/* webpackIgnore: true */ this.logtailPackage);\n\n // Handle different export patterns\n const LogtailClass = LogtailModule.default ?? LogtailModule.Logtail ?? LogtailModule;\n\n if (!LogtailClass) {\n logError(`Better Stack plugin: Could not find Logtail class in ${this.logtailPackage}`, {\n logtailPackage: this.logtailPackage,\n });\n this.enabled = false;\n return;\n }\n\n // Build configuration object\n const logtailConfig: any = {\n sourceToken,\n };\n\n // Add optional configuration\n if (\n mergedConfig.endpoint ??\n env.BETTER_STACK_INGESTING_URL ??\n env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL\n ) {\n logtailConfig.endpoint =\n mergedConfig.endpoint ??\n env.BETTER_STACK_INGESTING_URL ??\n env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL;\n }\n\n // Initialize the client\n this.client = new LogtailClass(logtailConfig) as T;\n\n this.initialized = true;\n } catch (error) {\n logError(`Failed to import Logtail package '${this.logtailPackage}'`, {\n error,\n logtailPackage: this.logtailPackage,\n });\n this.enabled = false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.client && this.initialized) {\n await this.client.flush();\n this.initialized = false;\n }\n }\n\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n const errorObj = error instanceof Error ? error : new Error(String(error));\n\n // Build structured data\n const data = {\n error: {\n name: errorObj.name,\n message: errorObj.message,\n stack: errorObj.stack,\n },\n context: context?.extra,\n tags: context?.tags,\n user: context?.user ?? this.currentUser,\n breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT),\n };\n\n this.client.error(errorObj.message, data);\n }\n\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Build structured data\n const data = {\n level,\n context: context?.extra,\n tags: context?.tags,\n user: context?.user ?? this.currentUser,\n breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT),\n };\n\n // Map log levels to Logtail methods\n switch (level) {\n case 'debug':\n this.client.debug(message, data);\n break;\n case 'warning':\n this.client.warn(message, data);\n break;\n case 'error':\n this.client.error(message, data);\n break;\n case 'info':\n default:\n this.client.info(message, data);\n break;\n }\n }\n\n setUser(user: ObservabilityUser | null): void {\n if (!this.enabled) return;\n this.currentUser = user;\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n if (!this.enabled) return;\n\n const enriched = {\n ...breadcrumb,\n timestamp: breadcrumb.timestamp ?? Date.now() / 1000,\n };\n\n // Use circular buffer to avoid array reallocation\n if (this.breadcrumbs.length < MAX_BREADCRUMBS_STORED) {\n this.breadcrumbs.push(enriched);\n } else {\n // Overwrite oldest entry (circular buffer)\n this.breadcrumbs[this.breadcrumbIndex] = enriched;\n this.breadcrumbIndex = (this.breadcrumbIndex + 1) % MAX_BREADCRUMBS_STORED;\n }\n }\n\n /**\n * Get the most recent breadcrumbs in chronological order\n * @param count - Number of breadcrumbs to retrieve\n * @returns Array of recent breadcrumbs\n */\n private getRecentBreadcrumbs(count: number): Breadcrumb[] {\n const { length } = this.breadcrumbs;\n if (length === 0) return [];\n if (length <= count) return this.breadcrumbs.slice();\n\n // If buffer is not full yet, return last N items from end of array\n if (length < MAX_BREADCRUMBS_STORED) {\n return this.breadcrumbs.slice(length - count);\n }\n\n // Circular buffer logic:\n // - When the buffer is full, `this.breadcrumbIndex` points to the oldest entry (the next to be overwritten).\n // - The most recent breadcrumb is at index `(this.breadcrumbIndex - 1 + length) % length`.\n // - To get the last `count` breadcrumbs in chronological order, we start at\n // `(this.breadcrumbIndex - count + length) % length` and read `count` entries, wrapping around as needed.\n // - This ensures we always get the correct slice, even if the buffer has wrapped around.\n const result: Breadcrumb[] = [];\n const start = (this.breadcrumbIndex - count + length) % length;\n\n for (let i = 0; i < count; i++) {\n const index = (start + i) % length;\n const breadcrumb = this.breadcrumbs[index];\n if (breadcrumb) {\n result.push(breadcrumb);\n }\n }\n\n return result;\n }\n\n withScope(callback: (scope: any) => void): void {\n if (!this.enabled) return;\n\n try {\n // Simple scope implementation\n const scope = {\n setContext: (_key: string, _context: unknown) => {\n // Could store this for next log entry\n },\n setUser: (user: ObservabilityUser | null) => {\n this.setUser(user);\n },\n };\n callback(scope);\n } catch {\n // Gracefully handle scope errors\n }\n }\n\n async flush(_timeout?: number): Promise<boolean> {\n if (!this.enabled || !this.client) return true;\n\n try {\n await this.client.flush();\n return true;\n } catch (error) {\n logError('Better Stack flush error', { error });\n return false;\n }\n }\n}\n\n/**\n * Factory function to create a Better Stack plugin.\n *\n * Creates a configured BetterStackPlugin instance with optional configuration.\n * Auto-detects the appropriate @logtail package based on the environment.\n *\n * @param config - Optional Better Stack plugin configuration\n * @returns BetterStackPlugin instance\n *\n * @example\n * ```typescript\n * const betterstack = createBetterStackPlugin({\n * sourceToken: '...',\n * logLevel: 'info',\n * });\n * ```\n */\nexport const createBetterStackPlugin = <T extends LogtailClient = LogtailClient>(\n config?: BetterStackPluginConfig,\n): BetterStackPlugin<T> => {\n return new BetterStackPlugin<T>(config);\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/plugins/betterstack/env.d.ts
|
|
2
|
+
declare const env: Readonly<{
|
|
3
|
+
LOGTAIL_SOURCE_TOKEN?: string | undefined;
|
|
4
|
+
BETTERSTACK_SOURCE_TOKEN?: string | undefined;
|
|
5
|
+
BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
6
|
+
BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
7
|
+
BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
8
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN?: string | undefined;
|
|
9
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN?: string | undefined;
|
|
10
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
11
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
12
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
declare function safeEnv(): Readonly<{
|
|
15
|
+
LOGTAIL_SOURCE_TOKEN?: string | undefined;
|
|
16
|
+
BETTERSTACK_SOURCE_TOKEN?: string | undefined;
|
|
17
|
+
BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
18
|
+
BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
19
|
+
BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
20
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN?: string | undefined;
|
|
21
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN?: string | undefined;
|
|
22
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN?: string | undefined;
|
|
23
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL?: string | undefined;
|
|
24
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL?: "error" | "debug" | "info" | "warn" | "off" | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
type Env = typeof env;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { Env, env, safeEnv };
|
|
29
|
+
//# sourceMappingURL=plugins-betterstack-env.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins-betterstack-env.d.mts","names":[],"sources":["../src/plugins/betterstack/env.ts"],"mappings":";cAWa,GAAA,EAAG,QAAA;;;;;;;;;;;;iBA+CA,OAAA,CAAA,GAAO,QAAA;;;;;;;;;;;;KA0CX,GAAA,UAAa,GAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { logWarn } from "@od-oneapp/shared/logger";
|
|
2
|
+
import { createEnv } from "@t3-oss/env-core";
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
|
+
|
|
5
|
+
//#region src/plugins/betterstack/env.ts
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Better Stack (Logtail) environment configuration
|
|
8
|
+
* Better Stack (Logtail) environment configuration
|
|
9
|
+
* Updated to support official @logtail packages
|
|
10
|
+
*/
|
|
11
|
+
const env = createEnv({
|
|
12
|
+
server: {
|
|
13
|
+
LOGTAIL_SOURCE_TOKEN: z.string().optional(),
|
|
14
|
+
BETTERSTACK_SOURCE_TOKEN: z.string().optional(),
|
|
15
|
+
BETTER_STACK_SOURCE_TOKEN: z.string().optional(),
|
|
16
|
+
BETTER_STACK_INGESTING_URL: z.string().url().optional(),
|
|
17
|
+
BETTER_STACK_LOG_LEVEL: z.enum([
|
|
18
|
+
"debug",
|
|
19
|
+
"info",
|
|
20
|
+
"warn",
|
|
21
|
+
"error",
|
|
22
|
+
"off"
|
|
23
|
+
]).optional()
|
|
24
|
+
},
|
|
25
|
+
client: {
|
|
26
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN: z.string().optional(),
|
|
27
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN: z.string().optional(),
|
|
28
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN: z.string().optional(),
|
|
29
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL: z.string().url().optional(),
|
|
30
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL: z.enum([
|
|
31
|
+
"debug",
|
|
32
|
+
"info",
|
|
33
|
+
"warn",
|
|
34
|
+
"error",
|
|
35
|
+
"off"
|
|
36
|
+
]).optional()
|
|
37
|
+
},
|
|
38
|
+
clientPrefix: "NEXT_PUBLIC_",
|
|
39
|
+
runtimeEnv: process.env,
|
|
40
|
+
emptyStringAsUndefined: true,
|
|
41
|
+
onInvalidAccess: (variable) => {
|
|
42
|
+
throw new Error(`❌ Attempted to access a server-side environment variable on the client: ${variable}`);
|
|
43
|
+
},
|
|
44
|
+
onValidationError: (error) => {
|
|
45
|
+
logWarn("Better Stack environment validation failed", { error });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Safe environment access for non-Next.js contexts.
|
|
50
|
+
*
|
|
51
|
+
* Provides fallback environment variable access for Node.js, workers, and test environments
|
|
52
|
+
* where the validated env object may not be available. Returns fallback values with proper
|
|
53
|
+
* priority handling for legacy and official Better Stack variable names.
|
|
54
|
+
*
|
|
55
|
+
* @returns Environment object with Better Stack configuration values
|
|
56
|
+
*/
|
|
57
|
+
function safeEnv() {
|
|
58
|
+
if (env) return env;
|
|
59
|
+
return {
|
|
60
|
+
LOGTAIL_SOURCE_TOKEN: process.env.LOGTAIL_SOURCE_TOKEN ?? process.env.BETTERSTACK_SOURCE_TOKEN ?? "",
|
|
61
|
+
BETTERSTACK_SOURCE_TOKEN: process.env.BETTERSTACK_SOURCE_TOKEN ?? process.env.LOGTAIL_SOURCE_TOKEN ?? "",
|
|
62
|
+
NEXT_PUBLIC_LOGTAIL_TOKEN: process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? "",
|
|
63
|
+
NEXT_PUBLIC_BETTERSTACK_TOKEN: process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? "",
|
|
64
|
+
BETTER_STACK_SOURCE_TOKEN: process.env.BETTER_STACK_SOURCE_TOKEN ?? process.env.LOGTAIL_SOURCE_TOKEN ?? process.env.BETTERSTACK_SOURCE_TOKEN ?? "",
|
|
65
|
+
BETTER_STACK_INGESTING_URL: process.env.BETTER_STACK_INGESTING_URL ?? "",
|
|
66
|
+
BETTER_STACK_LOG_LEVEL: process.env.BETTER_STACK_LOG_LEVEL ?? "info",
|
|
67
|
+
NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN: process.env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ?? process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? "",
|
|
68
|
+
NEXT_PUBLIC_BETTER_STACK_INGESTING_URL: process.env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL ?? "",
|
|
69
|
+
NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL: process.env.NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL ?? "info"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { env, safeEnv };
|
|
75
|
+
//# sourceMappingURL=plugins-betterstack-env.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins-betterstack-env.mjs","names":[],"sources":["../src/plugins/betterstack/env.ts"],"sourcesContent":["/**\n * @fileoverview Better Stack (Logtail) environment configuration\n * Better Stack (Logtail) environment configuration\n * Updated to support official @logtail packages\n */\n\nimport { logWarn } from '@repo/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\n// Create validated env object\nexport const env = createEnv({\n server: {\n // Legacy support\n LOGTAIL_SOURCE_TOKEN: z.string().optional(),\n BETTERSTACK_SOURCE_TOKEN: z.string().optional(),\n\n // Official Better Stack environment variables\n BETTER_STACK_SOURCE_TOKEN: z.string().optional(),\n BETTER_STACK_INGESTING_URL: z.string().url().optional(),\n BETTER_STACK_LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error', 'off']).optional(),\n },\n client: {\n // Legacy support\n NEXT_PUBLIC_LOGTAIL_TOKEN: z.string().optional(),\n NEXT_PUBLIC_BETTERSTACK_TOKEN: z.string().optional(),\n\n // Official Better Stack client environment variables\n NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN: z.string().optional(),\n NEXT_PUBLIC_BETTER_STACK_INGESTING_URL: z.string().url().optional(),\n NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL: z\n .enum(['debug', 'info', 'warn', 'error', 'off'])\n .optional(),\n },\n clientPrefix: 'NEXT_PUBLIC_',\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: error => {\n logWarn('Better Stack environment validation failed', { error });\n // Don't throw in packages - use fallbacks\n return undefined as never;\n },\n});\n\n/**\n * Safe environment access for non-Next.js contexts.\n *\n * Provides fallback environment variable access for Node.js, workers, and test environments\n * where the validated env object may not be available. Returns fallback values with proper\n * priority handling for legacy and official Better Stack variable names.\n *\n * @returns Environment object with Better Stack configuration values\n */\nexport function safeEnv() {\n if (env) return env;\n\n // Fallback values for resilience with proper priority\n return {\n // Legacy support\n LOGTAIL_SOURCE_TOKEN:\n process.env.LOGTAIL_SOURCE_TOKEN ?? process.env.BETTERSTACK_SOURCE_TOKEN ?? '',\n BETTERSTACK_SOURCE_TOKEN:\n process.env.BETTERSTACK_SOURCE_TOKEN ?? process.env.LOGTAIL_SOURCE_TOKEN ?? '',\n NEXT_PUBLIC_LOGTAIL_TOKEN:\n process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? '',\n NEXT_PUBLIC_BETTERSTACK_TOKEN:\n process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? '',\n\n // Official Better Stack (preferred)\n BETTER_STACK_SOURCE_TOKEN:\n process.env.BETTER_STACK_SOURCE_TOKEN ??\n process.env.LOGTAIL_SOURCE_TOKEN ??\n process.env.BETTERSTACK_SOURCE_TOKEN ??\n '',\n BETTER_STACK_INGESTING_URL: process.env.BETTER_STACK_INGESTING_URL ?? '',\n BETTER_STACK_LOG_LEVEL:\n (process.env.BETTER_STACK_LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error' | 'off') ?? 'info',\n NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN:\n process.env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ??\n process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ??\n '',\n NEXT_PUBLIC_BETTER_STACK_INGESTING_URL:\n process.env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL ?? '',\n NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL:\n (process.env.NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL as\n | 'debug'\n | 'info'\n | 'warn'\n | 'error'\n | 'off') ?? 'info',\n };\n}\n\n// Export type\nexport type Env = typeof env;\n"],"mappings":";;;;;;;;;;AAWA,MAAa,MAAM,UAAU;CAC3B,QAAQ;EAEN,sBAAsB,EAAE,QAAQ,CAAC,UAAU;EAC3C,0BAA0B,EAAE,QAAQ,CAAC,UAAU;EAG/C,2BAA2B,EAAE,QAAQ,CAAC,UAAU;EAChD,4BAA4B,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;EACvD,wBAAwB,EAAE,KAAK;GAAC;GAAS;GAAQ;GAAQ;GAAS;GAAM,CAAC,CAAC,UAAU;EACrF;CACD,QAAQ;EAEN,2BAA2B,EAAE,QAAQ,CAAC,UAAU;EAChD,+BAA+B,EAAE,QAAQ,CAAC,UAAU;EAGpD,uCAAuC,EAAE,QAAQ,CAAC,UAAU;EAC5D,wCAAwC,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;EACnE,oCAAoC,EACjC,KAAK;GAAC;GAAS;GAAQ;GAAQ;GAAS;GAAM,CAAC,CAC/C,UAAU;EACd;CACD,cAAc;CACd,YAAY,QAAQ;CACpB,wBAAwB;CACxB,kBAAkB,aAAqB;AACrC,QAAM,IAAI,MACR,2EAA2E,WAC5E;;CAEH,oBAAmB,UAAS;AAC1B,UAAQ,8CAA8C,EAAE,OAAO,CAAC;;CAInE,CAAC;;;;;;;;;;AAWF,SAAgB,UAAU;AACxB,KAAI,IAAK,QAAO;AAGhB,QAAO;EAEL,sBACE,QAAQ,IAAI,wBAAwB,QAAQ,IAAI,4BAA4B;EAC9E,0BACE,QAAQ,IAAI,4BAA4B,QAAQ,IAAI,wBAAwB;EAC9E,2BACE,QAAQ,IAAI,6BAA6B,QAAQ,IAAI,iCAAiC;EACxF,+BACE,QAAQ,IAAI,iCAAiC,QAAQ,IAAI,6BAA6B;EAGxF,2BACE,QAAQ,IAAI,6BACZ,QAAQ,IAAI,wBACZ,QAAQ,IAAI,4BACZ;EACF,4BAA4B,QAAQ,IAAI,8BAA8B;EACtE,wBACG,QAAQ,IAAI,0BAA0E;EACzF,uCACE,QAAQ,IAAI,yCACZ,QAAQ,IAAI,6BACZ,QAAQ,IAAI,iCACZ;EACF,wCACE,QAAQ,IAAI,0CAA0C;EACxD,oCACG,QAAQ,IAAI,sCAKC;EACjB"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { n as ObservabilityServerPlugin, t as ObservabilityPlugin } from "./plugin-Bfq-o3nr.mjs";
|
|
2
|
+
import { n as BetterStackPluginConfig, r as createBetterStackPlugin, t as BetterStackPlugin } from "./plugin-CaQxviDs.mjs";
|
|
3
|
+
import { Env, env, safeEnv } from "./plugins-betterstack-env.mjs";
|
|
4
|
+
export { BetterStackPlugin, type BetterStackPluginConfig, type Env, type ObservabilityPlugin, type ObservabilityServerPlugin, createBetterStackPlugin, env, safeEnv };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { a as Breadcrumb, f as ObservabilityUser, l as ObservabilityContext, n as ObservabilityServerPlugin, o as LogLevel, r as PluginFactory, t as ObservabilityPlugin } from "./plugin-Bfq-o3nr.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/console/index.d.ts
|
|
4
|
+
interface ConsolePluginConfig {
|
|
5
|
+
prefix?: string;
|
|
6
|
+
logLevel?: LogLevel;
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
colors?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare class ConsolePlugin implements ObservabilityPlugin<Console> {
|
|
11
|
+
name: string;
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
protected prefix: string;
|
|
14
|
+
private colors;
|
|
15
|
+
private isBrowser;
|
|
16
|
+
constructor(config?: ConsolePluginConfig);
|
|
17
|
+
initialize(): Promise<void>;
|
|
18
|
+
shutdown(): Promise<void>;
|
|
19
|
+
getClient(): Console | undefined;
|
|
20
|
+
captureException(error: Error | unknown, context?: ObservabilityContext): void;
|
|
21
|
+
captureMessage(message: string, level?: LogLevel, context?: ObservabilityContext): void;
|
|
22
|
+
setUser(user: ObservabilityUser | null): void;
|
|
23
|
+
addBreadcrumb(breadcrumb: Breadcrumb): void;
|
|
24
|
+
withScope(callback: (scope: any) => void): void;
|
|
25
|
+
flush(): Promise<boolean>;
|
|
26
|
+
private formatContext;
|
|
27
|
+
private getBrowserColorCSS;
|
|
28
|
+
private getAnsiColorCode;
|
|
29
|
+
private getLogMethod;
|
|
30
|
+
private getLevelLabel;
|
|
31
|
+
}
|
|
32
|
+
declare class ConsoleServerPlugin extends ConsolePlugin implements ObservabilityServerPlugin<Console> {}
|
|
33
|
+
declare const createConsolePlugin: PluginFactory<ConsolePluginConfig, ConsolePlugin>;
|
|
34
|
+
declare const createConsoleServerPlugin: PluginFactory<ConsolePluginConfig, ConsoleServerPlugin>;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ConsolePlugin, ConsolePluginConfig, ConsoleServerPlugin, type ObservabilityPlugin, type ObservabilityServerPlugin, createConsolePlugin, createConsoleServerPlugin };
|
|
37
|
+
//# sourceMappingURL=plugins-console.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins-console.d.mts","names":[],"sources":["../src/plugins/console/index.ts"],"mappings":";;;UAuBiB,mBAAA;EACf,MAAA;EACA,QAAA,GAAW,QAAA;EACX,OAAA;EACA,MAAA;AAAA;AAAA,cAYW,aAAA,YAAyB,mBAAA,CAAoB,OAAA;EACxD,IAAA;EACA,OAAA;EAAA,UACU,MAAA;EAAA,QACF,MAAA;EAAA,QACA,SAAA;cAOI,MAAA,GAAQ,mBAAA;EAQd,UAAA,CAAA,GAAc,OAAA;EAId,QAAA,CAAA,GAAY,OAAA;EAIlB,SAAA,CAAA,GAAa,OAAA;EAIb,gBAAA,CAAiB,KAAA,EAAO,KAAA,YAAiB,OAAA,GAAU,oBAAA;EA0BnD,cAAA,CAAe,OAAA,UAAiB,KAAA,GAAO,QAAA,EAAmB,OAAA,GAAU,oBAAA;EAsCpE,OAAA,CAAQ,IAAA,EAAM,iBAAA;EAcd,aAAA,CAAc,UAAA,EAAY,UAAA;EAc1B,SAAA,CAAU,QAAA,GAAW,KAAA;EAkBf,KAAA,CAAA,GAAS,OAAA;EAAA,QAQP,aAAA;EAAA,QA+BA,kBAAA;EAAA,QAeA,gBAAA;EAAA,QAgBA,YAAA;EAAA,QAqBA,aAAA;AAAA;AAAA,cAoBG,mBAAA,SACH,aAAA,YACG,yBAAA,CAA0B,OAAA;AAAA,cAQ1B,mBAAA,EAAqB,aAAA,CAAc,mBAAA,EAAqB,aAAA;AAAA,cAYxD,yBAAA,EAA2B,aAAA,CACtC,mBAAA,EACA,mBAAA"}
|