1
+ import type { Client } from './client' ;
1
2
import { getClient , getCurrentScope } from './currentScopes' ;
2
3
import { DEBUG_BUILD } from './debug-build' ;
4
+ import type { Scope } from './scope' ;
3
5
import { getDynamicSamplingContextFromScope } from './tracing' ;
4
6
import type { DynamicSamplingContext , LogEnvelope , LogItem } from './types-hoist/envelope' ;
5
7
import type { Log , LogAttribute , LogSeverityLevel } from './types-hoist/log' ;
@@ -24,20 +26,7 @@ export function createLogEnvelopeItem(log: Log): LogItem {
24
26
*
25
27
* @params log - the log object which will be sent
26
28
*/
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 {
41
30
const dsc = getDynamicSamplingContextFromScope ( client , scope ) ;
42
31
43
32
const dsn = client . getDsn ( ) ;
@@ -46,17 +35,8 @@ function addLog(log: Log): void {
46
35
trace : dropUndefinedKeys ( dsc ) as DynamicSamplingContext ,
47
36
...( dsn ? { dsn : dsnToString ( dsn ) } : { } ) ,
48
37
} ;
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 ) ] ) ;
57
38
58
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
59
- void client . sendEnvelope ( envelope ) ;
39
+ return createEnvelope < LogEnvelope > ( headers , logs . map ( createLogEnvelopeItem ) ) ;
60
40
}
61
41
62
42
function valueToAttribute ( key : string , value : unknown ) : LogAttribute {
@@ -84,13 +64,56 @@ function valueToAttribute(key: string, value: unknown): LogAttribute {
84
64
}
85
65
}
86
66
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
+
87
98
/**
88
99
* A utility function to be able to create methods like Sentry.info`...`
89
100
*
90
101
* The first parameter is bound with, e.g., const info = captureLog.bind(null, 'info')
91
102
* The other parameters are in the format to be passed a tagged template, Sentry.info`hello ${world}`
92
103
*/
93
104
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
+
94
117
const message = Array . isArray ( messages )
95
118
? messages . reduce ( ( acc , str , i ) => acc + str + ( values [ i ] ?? '' ) , '' )
96
119
: messages ;
@@ -103,11 +126,18 @@ export function captureLog(level: LogSeverityLevel, messages: string[] | string,
103
126
} ,
104
127
} ) ;
105
128
}
106
- addLog ( {
129
+
130
+ const scope = getCurrentScope ( ) ;
131
+
132
+ const log : Log = {
107
133
severityText : level ,
108
134
body : {
109
135
stringValue : message ,
110
136
} ,
111
137
attributes : attributes ,
112
- } ) ;
138
+ timeUnixNano : `${ new Date ( ) . getTime ( ) . toString ( ) } 000000` ,
139
+ traceId : scope . getPropagationContext ( ) . traceId ,
140
+ } ;
141
+
142
+ addToLogBuffer ( client , log , scope ) ;
113
143
}
0 commit comments