feat: 增加debug参数
This commit is contained in:
parent
fc95159945
commit
e5844bbfe9
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -132,6 +132,7 @@ export interface LightConfig {
|
|||
release?: string;
|
||||
environment?: string;
|
||||
enabled?: boolean;
|
||||
debug?: boolean;
|
||||
sampleRate?: number;
|
||||
maxQueueSize?: number;
|
||||
flushInterval?: number;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
export declare function setDebug(enabled: boolean): void;
|
||||
export declare function isDebugEnabled(): boolean;
|
||||
export declare function logDebug(tag: string, message: string, data?: unknown): void;
|
||||
export declare function logError(tag: string, message: string, error?: unknown): void;
|
||||
|
|
@ -3,6 +3,7 @@ import { parseDSN } from '../utils/dsn';
|
|||
import { now } from '../utils/helper';
|
||||
import { computeFingerprint } from '../utils/hash';
|
||||
import { parseStackTrace } from '../utils/stacktrace';
|
||||
import { logDebug, setDebug } from '../utils/logger';
|
||||
import { ConfigManager } from './ConfigManager';
|
||||
import { EventBus } from './EventBus';
|
||||
import { EventQueue } from './EventQueue';
|
||||
|
|
@ -33,6 +34,9 @@ class Client implements LightClient {
|
|||
throw new Error('DSN is required');
|
||||
}
|
||||
|
||||
setDebug(config.debug === true);
|
||||
logDebug('Client', 'Initializing SDK', { dsn: config.dsn, debug: config.debug, enabled: config.enabled });
|
||||
|
||||
this.dsn = parseDSN(config.dsn);
|
||||
this.configManager = new ConfigManager(config);
|
||||
this.eventBus = new EventBus();
|
||||
|
|
@ -51,6 +55,7 @@ class Client implements LightClient {
|
|||
);
|
||||
|
||||
this.enabled = this.configManager.get('enabled') !== false;
|
||||
logDebug('Client', 'SDK initialized', { enabled: this.enabled });
|
||||
}
|
||||
|
||||
init(): void {
|
||||
|
|
@ -60,16 +65,23 @@ class Client implements LightClient {
|
|||
}
|
||||
|
||||
private async flushEvents(events: SentryEvent[]): Promise<void> {
|
||||
logDebug('Client', 'flushEvents start', { eventCount: events.length });
|
||||
|
||||
const processedEvents: SentryEvent[] = [];
|
||||
|
||||
for (const event of events) {
|
||||
const processed = this.pluginManager.applyBeforeReport(event);
|
||||
if (processed) {
|
||||
processedEvents.push(processed);
|
||||
} else {
|
||||
logDebug('Client', 'Event filtered by beforeReport plugin', { type: event.type, message: 'message' in event ? event.message : undefined });
|
||||
}
|
||||
}
|
||||
|
||||
if (processedEvents.length === 0) return;
|
||||
if (processedEvents.length === 0) {
|
||||
logDebug('Client', 'flushEvents: all events filtered by beforeReport');
|
||||
return;
|
||||
}
|
||||
|
||||
let isFirstInBatch = true;
|
||||
const finalEvents: SentryEvent[] = [];
|
||||
|
|
@ -80,14 +92,22 @@ class Client implements LightClient {
|
|||
|
||||
const beforeSend = this.configManager.get('beforeSend');
|
||||
const afterBeforeSend = beforeSend ? beforeSend(withConfig) : withConfig;
|
||||
if (!afterBeforeSend) continue;
|
||||
if (!afterBeforeSend) {
|
||||
logDebug('Client', 'Event filtered by beforeSend', { type: event.type });
|
||||
continue;
|
||||
}
|
||||
|
||||
finalEvents.push(afterBeforeSend);
|
||||
}
|
||||
|
||||
if (finalEvents.length === 0) return;
|
||||
if (finalEvents.length === 0) {
|
||||
logDebug('Client', 'flushEvents: all events filtered by beforeSend');
|
||||
return;
|
||||
}
|
||||
|
||||
logDebug('Client', 'Reporting events', { count: finalEvents.length });
|
||||
await this.reporter.report(finalEvents);
|
||||
logDebug('Client', 'Report completed successfully');
|
||||
this.configManager.markContextReported();
|
||||
|
||||
for (const event of finalEvents) {
|
||||
|
|
@ -140,12 +160,23 @@ class Client implements LightClient {
|
|||
}
|
||||
|
||||
captureException(error: Error | unknown): void {
|
||||
if (!this.enabled) return;
|
||||
logDebug('Client', 'captureException called', { error: error instanceof Error ? error.message : String(error) });
|
||||
|
||||
if (!this.enabled) {
|
||||
logDebug('Client', 'captureException skipped: SDK disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
const errorEvent = this.buildErrorEvent(error);
|
||||
if (this.configManager.isIgnoredError(errorEvent.message)) return;
|
||||
logDebug('Client', 'Error event built', { type: errorEvent.type, message: errorEvent.message, fingerprint: (errorEvent as ErrorEvent).fingerprint });
|
||||
|
||||
if (this.configManager.isIgnoredError(errorEvent.message)) {
|
||||
logDebug('Client', 'captureException skipped: error ignored by ignoreErrors');
|
||||
return;
|
||||
}
|
||||
|
||||
errorEvent.breadcrumbs = [...this.breadcrumbs];
|
||||
logDebug('Client', 'Enqueue error event', { breadcrumbs: this.breadcrumbs.length });
|
||||
this.queue.enqueue(errorEvent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { SentryEvent, ErrorEvent, CountEvent } from '../types';
|
||||
import { EventBus } from './EventBus';
|
||||
import { now } from '../utils/helper';
|
||||
import { logDebug } from '../utils/logger';
|
||||
|
||||
interface DedupeEntry {
|
||||
count: number;
|
||||
|
|
@ -124,7 +125,12 @@ export class EventQueue {
|
|||
}
|
||||
|
||||
enqueue(event: SentryEvent): void {
|
||||
if (this.paused) return;
|
||||
logDebug('EventQueue', 'enqueue called', { type: event.type, level: event.level, message: 'message' in event ? (event as { message: string }).message : undefined });
|
||||
|
||||
if (this.paused) {
|
||||
logDebug('EventQueue', 'enqueue skipped: queue paused (infinite loop detected)');
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleanupExpiredDedupeEntries();
|
||||
|
||||
|
|
@ -132,6 +138,7 @@ export class EventQueue {
|
|||
|
||||
if (fingerprint) {
|
||||
if (this.checkInfiniteLoop(fingerprint)) {
|
||||
logDebug('EventQueue', 'enqueue skipped: infinite loop detected', { fingerprint });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -148,23 +155,29 @@ export class EventQueue {
|
|||
pending.count++;
|
||||
pending.ts_end = currentTime;
|
||||
}
|
||||
logDebug('EventQueue', 'enqueue skipped: deduped (count >= 3)', { fingerprint, count: existing.count });
|
||||
return;
|
||||
}
|
||||
existing.count++;
|
||||
existing.lastTime = currentTime;
|
||||
logDebug('EventQueue', 'Dedup count incremented', { fingerprint, count: existing.count });
|
||||
} else {
|
||||
this.dedupeMap.set(fingerprint, { count: 1, lastTime: currentTime, firstReported: true });
|
||||
this.pendingCounts.delete(fingerprint);
|
||||
logDebug('EventQueue', 'Dedup entry reset (expired)', { fingerprint });
|
||||
}
|
||||
} else {
|
||||
this.dedupeMap.set(fingerprint, { count: 1, lastTime: currentTime, firstReported: false });
|
||||
logDebug('EventQueue', 'New dedup entry created', { fingerprint });
|
||||
}
|
||||
}
|
||||
|
||||
this.queue.push(event);
|
||||
logDebug('EventQueue', 'Event added to queue', { queueSize: this.queue.length });
|
||||
this.eventBus.emit('event', event);
|
||||
|
||||
if (this.queue.length >= this.maxSize) {
|
||||
logDebug('EventQueue', 'Queue reached maxSize, triggering flush', { maxSize: this.maxSize });
|
||||
this.flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -211,8 +224,16 @@ export class EventQueue {
|
|||
}
|
||||
|
||||
async flush(): Promise<void> {
|
||||
if (this.queue.length === 0 && this.pendingCounts.size === 0) return;
|
||||
if (this.isFlushing) return;
|
||||
logDebug('EventQueue', 'flush called', { queueSize: this.queue.length, pendingCounts: this.pendingCounts.size, isFlushing: this.isFlushing });
|
||||
|
||||
if (this.queue.length === 0 && this.pendingCounts.size === 0) {
|
||||
logDebug('EventQueue', 'flush skipped: queue is empty');
|
||||
return;
|
||||
}
|
||||
if (this.isFlushing) {
|
||||
logDebug('EventQueue', 'flush skipped: already flushing');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isFlushing = true;
|
||||
|
||||
|
|
@ -220,14 +241,18 @@ export class EventQueue {
|
|||
const countEvents = this.buildCountEvents();
|
||||
const allEvents = [...events, ...countEvents];
|
||||
|
||||
logDebug('EventQueue', 'flush events to callback', { total: allEvents.length, events: events.length, countEvents: countEvents.length });
|
||||
|
||||
this.lastFlushTime = now();
|
||||
this.eventBus.emit('report', allEvents);
|
||||
|
||||
try {
|
||||
await this.flushCallback(allEvents);
|
||||
this.pendingCounts.clear();
|
||||
logDebug('EventQueue', 'flush completed successfully');
|
||||
this.eventBus.emit('reported', allEvents);
|
||||
} catch (e) {
|
||||
logDebug('EventQueue', 'flush failed, returning events to queue', { error: e instanceof Error ? e.message : String(e) });
|
||||
events.forEach(evt => this.queue.unshift(evt));
|
||||
throw e;
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { DSNInfo, SentryEvent, ErrorEvent } from '../types';
|
|||
import { getEnvelopeUrl } from '../utils/dsn';
|
||||
import { now, generateEventId } from '../utils/helper';
|
||||
import { encodeFields, FIELD_ENCODE_MAP } from '../utils/field-encoder';
|
||||
import { logDebug, logError } from '../utils/logger';
|
||||
|
||||
export class Reporter {
|
||||
private dsn: DSNInfo;
|
||||
|
|
@ -16,25 +17,37 @@ export class Reporter {
|
|||
}
|
||||
|
||||
async report(events: SentryEvent[]): Promise<void> {
|
||||
if (events.length === 0) return;
|
||||
logDebug('Reporter', 'report called', { eventCount: events.length });
|
||||
|
||||
if (events.length === 0) {
|
||||
logDebug('Reporter', 'report skipped: empty events');
|
||||
return;
|
||||
}
|
||||
|
||||
const envelope = this.buildEnvelope(events);
|
||||
const url = getEnvelopeUrl(this.dsn);
|
||||
logDebug('Reporter', 'Envelope built', { envelopeSize: envelope.length, url });
|
||||
|
||||
let retries = 0;
|
||||
while (retries <= this.maxRetries) {
|
||||
try {
|
||||
logDebug('Reporter', `Sending request (attempt ${retries + 1}/${this.maxRetries + 1})`);
|
||||
await this.send(envelope, false);
|
||||
logDebug('Reporter', 'Request succeeded');
|
||||
return;
|
||||
} catch (e) {
|
||||
const status = (e as { status?: number }).status;
|
||||
logError('Reporter', `Request failed (attempt ${retries + 1})`, { status, error: e });
|
||||
if (status && status >= 400 && status < 500) {
|
||||
throw e;
|
||||
}
|
||||
retries++;
|
||||
if (retries > this.maxRetries) {
|
||||
logError('Reporter', 'All retries exhausted');
|
||||
throw e;
|
||||
}
|
||||
const backoff = Math.min(this.retryDelay * Math.pow(2, retries - 1), 5000);
|
||||
logDebug('Reporter', `Retrying in ${backoff}ms`);
|
||||
await this.delay(backoff);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { LightPlugin, LightClient, SentryEvent, LightConfig } from '../types';
|
||||
import { isObject } from '../utils/helper';
|
||||
import { logDebug } from '../utils/logger';
|
||||
|
||||
interface SampleRateConfig {
|
||||
error?: number;
|
||||
|
|
@ -73,7 +74,13 @@ class SamplingPlugin implements LightPlugin {
|
|||
}
|
||||
|
||||
beforeReport(event: SentryEvent): SentryEvent | null {
|
||||
if (!this.shouldSample(event)) {
|
||||
const sampled = this.shouldSample(event);
|
||||
if (!sampled) {
|
||||
logDebug('SamplingPlugin', 'Event dropped by sampling', {
|
||||
type: event.type,
|
||||
globalRate: (this.client.config as LightConfig).sampleRate ?? 1,
|
||||
typeRate: this.getTypeRate(event),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ export interface LightConfig {
|
|||
release?: string;
|
||||
environment?: string;
|
||||
enabled?: boolean;
|
||||
debug?: boolean;
|
||||
sampleRate?: number;
|
||||
maxQueueSize?: number;
|
||||
flushInterval?: number;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
let debugEnabled = false;
|
||||
|
||||
export function setDebug(enabled: boolean): void {
|
||||
debugEnabled = enabled;
|
||||
}
|
||||
|
||||
export function isDebugEnabled(): boolean {
|
||||
return debugEnabled;
|
||||
}
|
||||
|
||||
export function logDebug(tag: string, message: string, data?: unknown): void {
|
||||
if (!debugEnabled) return;
|
||||
const timestamp = new Date().toISOString();
|
||||
const prefix = `[LightSDK][${tag}]`;
|
||||
if (data !== undefined) {
|
||||
console.log(`${prefix} ${timestamp} ${message}`, data);
|
||||
} else {
|
||||
console.log(`${prefix} ${timestamp} ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function logError(tag: string, message: string, error?: unknown): void {
|
||||
if (!debugEnabled) return;
|
||||
const timestamp = new Date().toISOString();
|
||||
const prefix = `[LightSDK][${tag}][ERROR]`;
|
||||
if (error !== undefined) {
|
||||
console.error(`${prefix} ${timestamp} ${message}`, error);
|
||||
} else {
|
||||
console.error(`${prefix} ${timestamp} ${message}`);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue