Skip to content

Commit a41aed6

Browse files
committed
allow for multiple logs to be flushed in the same envelope
1 parent 1c95817 commit a41aed6

File tree

2 files changed

+61
-31
lines changed

2 files changed

+61
-31
lines changed

packages/core/src/exports.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -344,21 +344,21 @@ export const _experiment_log = {
344344
* A utility to record a log with level 'INFO' and send it to sentry.
345345
*
346346
* Logs represent a message and some parameters which provide context for a trace or error.
347-
* Ex: sentry.logInfo`user ${username} just bought ${item}!`
347+
* Ex: Sentry._experiment_log.info`user ${username} just bought ${item}!`
348348
*/
349349
info: captureLog.bind(null, 'info'),
350350
/**
351351
* A utility to record a log with level 'ERROR' and send it to sentry.
352352
*
353353
* Logs represent a message and some parameters which provide context for a trace or error.
354-
* Ex: sentry.logError`user ${username} just bought ${item}!`
354+
* Ex: Sentry._experiment_log.error`user ${username} just bought ${item}!`
355355
*/
356356
error: captureLog.bind(null, 'error'),
357357
/**
358-
* A utility to record a log with level 'WARNING' and send it to sentry.
358+
* A utility to record a log with level 'WARN' and send it to sentry.
359359
*
360360
* Logs represent a message and some parameters which provide context for a trace or error.
361-
* Ex: sentry.logWarning`user ${username} just bought ${item}!`
361+
* Ex: Sentry._experiment_log.warn`user ${username} just bought ${item}!`
362362
*/
363-
warning: captureLog.bind(null, 'warning'),
363+
warn: captureLog.bind(null, 'warn'),
364364
};

packages/core/src/log.ts

+56-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { Client } from './client';
12
import { getClient, getCurrentScope } from './currentScopes';
23
import { DEBUG_BUILD } from './debug-build';
4+
import type { Scope } from './scope';
35
import { getDynamicSamplingContextFromScope } from './tracing';
46
import type { DynamicSamplingContext, LogEnvelope, LogItem } from './types-hoist/envelope';
57
import type { Log, LogAttribute, LogSeverityLevel } from './types-hoist/log';
@@ -24,20 +26,7 @@ export function createLogEnvelopeItem(log: Log): LogItem {
2426
*
2527
* @params log - the log object which will be sent
2628
*/
27-
function addLog(log: Log): void {
28-
const client = getClient();
29-
30-
if (!client) {
31-
DEBUG_BUILD && logger.warn('No client available, log will not be captured.');
32-
return;
33-
}
34-
35-
if (!client.getOptions()._experiments?.enableLogs) {
36-
DEBUG_BUILD && logger.warn('logging option not enabled, log will not be captured.');
37-
return;
38-
}
39-
40-
const scope = getCurrentScope();
29+
function createLogEnvelope(logs: Log[], client: Client, scope: Scope): LogEnvelope {
4130
const dsc = getDynamicSamplingContextFromScope(client, scope);
4231

4332
const dsn = client.getDsn();
@@ -46,17 +35,8 @@ function addLog(log: Log): void {
4635
trace: dropUndefinedKeys(dsc) as DynamicSamplingContext,
4736
...(dsn ? { dsn: dsnToString(dsn) } : {}),
4837
};
49-
if (!log.traceId) {
50-
log.traceId = dsc.trace_id;
51-
}
52-
if (!log.timeUnixNano) {
53-
log.timeUnixNano = `${new Date().getTime().toString()}000000`;
54-
}
55-
56-
const envelope = createEnvelope<LogEnvelope>(headers, [createLogEnvelopeItem(log)]);
5738

58-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
59-
void client.sendEnvelope(envelope);
39+
return createEnvelope<LogEnvelope>(headers, logs.map(createLogEnvelopeItem));
6040
}
6141

6242
function valueToAttribute(key: string, value: unknown): LogAttribute {
@@ -84,13 +64,56 @@ function valueToAttribute(key: string, value: unknown): LogAttribute {
8464
}
8565
}
8666

67+
let GLOBAL_LOG_BUFFER: Log[] = [];
68+
69+
let isFlushingLogs = false;
70+
71+
function addToLogBuffer(client: Client, log: Log, scope: Scope): void {
72+
function sendLogs(flushedLogs: Log[]): void {
73+
const envelope = createLogEnvelope(flushedLogs, client, scope);
74+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
75+
void client.sendEnvelope(envelope);
76+
}
77+
78+
if (GLOBAL_LOG_BUFFER.length >= 100) {
79+
sendLogs(GLOBAL_LOG_BUFFER);
80+
GLOBAL_LOG_BUFFER = [];
81+
} else {
82+
GLOBAL_LOG_BUFFER.push(log);
83+
}
84+
85+
// this is the first time logs have been enabled, let's kick off an interval to flush them
86+
// we should only do this once.
87+
if (!isFlushingLogs) {
88+
setInterval(() => {
89+
if (GLOBAL_LOG_BUFFER.length > 0) {
90+
sendLogs(GLOBAL_LOG_BUFFER);
91+
GLOBAL_LOG_BUFFER = [];
92+
}
93+
}, 5000);
94+
}
95+
isFlushingLogs = true;
96+
}
97+
8798
/**
8899
* A utility function to be able to create methods like Sentry.info`...`
89100
*
90101
* The first parameter is bound with, e.g., const info = captureLog.bind(null, 'info')
91102
* The other parameters are in the format to be passed a tagged template, Sentry.info`hello ${world}`
92103
*/
93104
export function captureLog(level: LogSeverityLevel, messages: string[] | string, ...values: unknown[]): void {
105+
const client = getClient();
106+
107+
if (!client) {
108+
DEBUG_BUILD && logger.warn('No client available, log will not be captured.');
109+
return;
110+
}
111+
112+
if (!client.getOptions()._experiments?.enableLogs) {
113+
DEBUG_BUILD && logger.warn('logging option not enabled, log will not be captured.');
114+
return;
115+
}
116+
94117
const message = Array.isArray(messages)
95118
? messages.reduce((acc, str, i) => acc + str + (values[i] ?? ''), '')
96119
: messages;
@@ -103,11 +126,18 @@ export function captureLog(level: LogSeverityLevel, messages: string[] | string,
103126
},
104127
});
105128
}
106-
addLog({
129+
130+
const scope = getCurrentScope();
131+
132+
const log: Log = {
107133
severityText: level,
108134
body: {
109135
stringValue: message,
110136
},
111137
attributes: attributes,
112-
});
138+
timeUnixNano: `${new Date().getTime().toString()}000000`,
139+
traceId: scope.getPropagationContext().traceId,
140+
};
141+
142+
addToLogBuffer(client, log, scope);
113143
}

0 commit comments

Comments
 (0)