1
1
import anyTest , { TestFn , ExecutionContext } from 'ava' ;
2
2
import { v4 as uuid4 } from 'uuid' ;
3
- import { DefaultLogger , LogEntry , defaultSinks } from '@temporalio/worker' ;
3
+ import {
4
+ DefaultLogger ,
5
+ InjectedSinks ,
6
+ LogEntry ,
7
+ LogLevel ,
8
+ LoggerSinks ,
9
+ Runtime ,
10
+ defaultSinks ,
11
+ } from '@temporalio/worker' ;
4
12
import { TestWorkflowEnvironment } from '@temporalio/testing' ;
13
+ import { WorkflowInfo } from '@temporalio/workflow' ;
5
14
import * as workflows from './workflows' ;
6
15
import { Worker } from './helpers' ;
7
16
@@ -11,9 +20,19 @@ interface Context {
11
20
}
12
21
const test = anyTest as TestFn < Context > ;
13
22
23
+ const recordedLogs : { [ workflowId : string ] : LogEntry [ ] } = { } ;
24
+
14
25
test . before ( async ( t ) => {
26
+ Runtime . install ( {
27
+ logger : new DefaultLogger ( 'DEBUG' , ( entry ) => {
28
+ const workflowId = ( entry . meta as any ) ?. workflowInfo ?. workflowId ?? ( entry . meta as any ) ?. workflowId ;
29
+ recordedLogs [ workflowId ] ??= [ ] ;
30
+ recordedLogs [ workflowId ] . push ( entry ) ;
31
+ } ) ,
32
+ } ) ;
33
+
15
34
t . context = {
16
- testEnv : await TestWorkflowEnvironment . createTimeSkipping ( ) ,
35
+ testEnv : await TestWorkflowEnvironment . createLocal ( ) ,
17
36
taskQueue : '' , // Will be set in beforeEach
18
37
} ;
19
38
} ) ;
@@ -26,27 +45,30 @@ test.after.always(async (t) => {
26
45
await t . context . testEnv ?. teardown ( ) ;
27
46
} ) ;
28
47
29
- async function withWorker ( t : ExecutionContext < Context > , p : Promise < any > ) : Promise < [ LogEntry , LogEntry ] > {
48
+ async function withWorker (
49
+ t : ExecutionContext < Context > ,
50
+ p : Promise < any > ,
51
+ workflowId : string
52
+ ) : Promise < [ LogEntry , LogEntry ] > {
30
53
const { nativeConnection } = t . context . testEnv ;
31
- const logs = Array < LogEntry > ( ) ;
32
- const logger = new DefaultLogger ( 'DEBUG' , ( entry ) => logs . push ( entry ) ) ;
33
54
const worker = await Worker . create ( {
34
55
connection : nativeConnection ,
35
56
taskQueue : t . context . taskQueue ,
36
57
workflowsPath : require . resolve ( './workflows' ) ,
37
- sinks : defaultSinks ( logger ) ,
38
58
} ) ;
39
59
await worker . runUntil ( p ) ;
60
+ const logs = recordedLogs [ workflowId ] ;
40
61
t . true ( logs . length >= 2 ) ;
41
62
return logs as [ LogEntry , LogEntry ] ;
42
63
}
43
64
44
- test . serial ( 'WorkflowInboundLogInterceptor logs when workflow completes' , async ( t ) => {
65
+ test ( 'WorkflowInboundLogInterceptor logs when workflow completes' , async ( t ) => {
45
66
const { client } = t . context . testEnv ;
46
67
const workflowId = uuid4 ( ) ;
47
68
const [ startLog , endLog ] = await withWorker (
48
69
t ,
49
- client . workflow . execute ( workflows . successString , { workflowId, taskQueue : t . context . taskQueue } )
70
+ client . workflow . execute ( workflows . successString , { workflowId, taskQueue : t . context . taskQueue } ) ,
71
+ workflowId
50
72
) ;
51
73
t . is ( startLog . level , 'DEBUG' ) ;
52
74
t . is ( startLog . message , 'Workflow started' ) ;
@@ -59,35 +81,121 @@ test.serial('WorkflowInboundLogInterceptor logs when workflow completes', async
59
81
t . is ( endLog . message , 'Workflow completed' ) ;
60
82
} ) ;
61
83
62
- test . serial ( 'WorkflowInboundLogInterceptor logs when workflow continues as new' , async ( t ) => {
84
+ test ( 'WorkflowInboundLogInterceptor logs when workflow continues as new' , async ( t ) => {
63
85
const { client } = t . context . testEnv ;
86
+ const workflowId = uuid4 ( ) ;
64
87
const [ _ , endLog ] = await withWorker (
65
88
t ,
66
89
t . throwsAsync (
67
90
client . workflow . execute ( workflows . continueAsNewSameWorkflow , {
68
91
args : [ 'execute' , 'execute' ] ,
69
- workflowId : uuid4 ( ) ,
92
+ workflowId,
70
93
taskQueue : t . context . taskQueue ,
71
94
followRuns : false ,
72
95
} )
73
- )
96
+ ) ,
97
+ workflowId
74
98
) ;
75
99
t . is ( endLog . level , 'DEBUG' ) ;
76
100
t . is ( endLog . message , 'Workflow continued as new' ) ;
77
101
} ) ;
78
102
79
- test . serial ( 'WorkflowInboundLogInterceptor logs warning when workflow fails' , async ( t ) => {
103
+ test ( 'WorkflowInboundLogInterceptor logs warning when workflow fails' , async ( t ) => {
80
104
const { client } = t . context . testEnv ;
105
+ const workflowId = uuid4 ( ) ;
81
106
const [ _ , endLog ] = await withWorker (
82
107
t ,
83
108
t . throwsAsync (
84
109
client . workflow . execute ( workflows . throwAsync , {
85
- workflowId : uuid4 ( ) ,
110
+ workflowId,
86
111
taskQueue : t . context . taskQueue ,
87
112
followRuns : false ,
88
113
} )
89
- )
114
+ ) ,
115
+ workflowId
90
116
) ;
91
117
t . is ( endLog . level , 'WARN' ) ;
92
118
t . is ( endLog . message , 'Workflow failed' ) ;
93
119
} ) ;
120
+
121
+ test ( '(Legacy) defaultSinks(logger) can be used to customize where logs are sent' , async ( t ) => {
122
+ const { client } = t . context . testEnv ;
123
+ const workflowId = uuid4 ( ) ;
124
+ const { nativeConnection } = t . context . testEnv ;
125
+ const logs = Array < LogEntry > ( ) ;
126
+ const logger = new DefaultLogger ( 'DEBUG' , ( entry ) => logs . push ( entry ) ) ;
127
+ const worker = await Worker . create ( {
128
+ connection : nativeConnection ,
129
+ taskQueue : t . context . taskQueue ,
130
+ workflowsPath : require . resolve ( './workflows' ) ,
131
+ // eslint-disable-next-line deprecation/deprecation
132
+ sinks : defaultSinks ( logger ) ,
133
+ } ) ;
134
+ await worker . runUntil (
135
+ client . workflow . execute ( workflows . successString , { workflowId, taskQueue : t . context . taskQueue } )
136
+ ) ;
137
+ t . false ( workflowId in recordedLogs ) ;
138
+ t . true ( logs . length >= 2 ) ;
139
+ const [ startLog , endLog ] = logs ;
140
+ t . is ( startLog . level , 'DEBUG' ) ;
141
+ t . is ( startLog . message , 'Workflow started' ) ;
142
+ t . is ( startLog . meta ?. workflowId , workflowId ) ;
143
+ t . true ( typeof startLog . meta ?. runId === 'string' ) ;
144
+ t . is ( startLog . meta ?. taskQueue , t . context . taskQueue ) ;
145
+ t . is ( startLog . meta ?. namespace , 'default' ) ;
146
+ t . is ( startLog . meta ?. workflowType , 'successString' ) ;
147
+ t . is ( endLog . level , 'DEBUG' ) ;
148
+ t . is ( endLog . message , 'Workflow completed' ) ;
149
+ } ) ;
150
+
151
+ test ( '(Legacy) Can register defaultWorkerLogger sink to customize where logs are sent' , async ( t ) => {
152
+ const { client } = t . context . testEnv ;
153
+ const workflowId = uuid4 ( ) ;
154
+ const { nativeConnection } = t . context . testEnv ;
155
+ const logs = Array < LogEntry > ( ) ;
156
+ const fn = ( level : LogLevel , _info : WorkflowInfo , message : string , attrs ?: Record < string , unknown > ) => {
157
+ logs . push ( { level, message, meta : attrs , timestampNanos : 0n } ) ;
158
+ } ;
159
+ const worker = await Worker . create ( {
160
+ connection : nativeConnection ,
161
+ taskQueue : t . context . taskQueue ,
162
+ workflowsPath : require . resolve ( './workflows' ) ,
163
+ // eslint-disable-next-line deprecation/deprecation
164
+ sinks : < InjectedSinks < LoggerSinks > > {
165
+ defaultWorkerLogger : {
166
+ trace : { fn : fn . bind ( undefined , 'TRACE' ) } ,
167
+ debug : { fn : fn . bind ( undefined , 'DEBUG' ) } ,
168
+ info : { fn : fn . bind ( undefined , 'INFO' ) } ,
169
+ warn : { fn : fn . bind ( undefined , 'WARN' ) } ,
170
+ error : { fn : fn . bind ( undefined , 'ERROR' ) } ,
171
+ } ,
172
+ } ,
173
+ } ) ;
174
+ await worker . runUntil (
175
+ client . workflow . execute ( workflows . successString , { workflowId, taskQueue : t . context . taskQueue } )
176
+ ) ;
177
+ t . false ( workflowId in recordedLogs ) ;
178
+ t . true ( logs . length >= 2 ) ;
179
+ const [ startLog , endLog ] = logs ;
180
+ t . is ( startLog . level , 'DEBUG' ) ;
181
+ t . is ( startLog . message , 'Workflow started' ) ;
182
+ t . is ( startLog . meta ?. workflowId , workflowId ) ;
183
+ t . true ( typeof startLog . meta ?. runId === 'string' ) ;
184
+ t . is ( startLog . meta ?. taskQueue , t . context . taskQueue ) ;
185
+ t . is ( startLog . meta ?. namespace , 'default' ) ;
186
+ t . is ( startLog . meta ?. workflowType , 'successString' ) ;
187
+ t . is ( endLog . level , 'DEBUG' ) ;
188
+ t . is ( endLog . message , 'Workflow completed' ) ;
189
+ } ) ;
190
+
191
+ test ( '(Legacy) Can explicitly call defaultWorkerLogger sink to emit logs' , async ( t ) => {
192
+ const { client } = t . context . testEnv ;
193
+ const workflowId = uuid4 ( ) ;
194
+ const [ _ , midLog ] = await withWorker (
195
+ t ,
196
+ client . workflow . execute ( workflows . useDepreatedLoggerSinkWorkflow , { workflowId, taskQueue : t . context . taskQueue } ) ,
197
+ workflowId
198
+ ) ;
199
+ t . is ( midLog . level , 'INFO' ) ;
200
+ t . is ( midLog . message , 'Log message from workflow' ) ;
201
+ } ) ;
0 commit comments