@output.ai/core 0.5.3 → 0.5.5
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@output.ai/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "The core module of the output framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"stacktrace-parser": "0.1.11",
|
|
41
41
|
"undici": "7.18.2",
|
|
42
42
|
"winston": "3.17.0",
|
|
43
|
-
"zod": "4.
|
|
43
|
+
"zod": "^4.3.6"
|
|
44
44
|
},
|
|
45
45
|
"license": "Apache-2.0",
|
|
46
46
|
"publishConfig": {
|
package/src/consts.js
CHANGED
|
@@ -87,6 +87,18 @@ describe( 'tracing/trace_engine', () => {
|
|
|
87
87
|
expect( localExecMock ).not.toHaveBeenCalled();
|
|
88
88
|
} );
|
|
89
89
|
|
|
90
|
+
it( 'addEventPhase() does not emit when kind is INTERNAL_STEP', async () => {
|
|
91
|
+
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
92
|
+
const { init, addEventPhase } = await loadTraceEngine();
|
|
93
|
+
await init();
|
|
94
|
+
|
|
95
|
+
addEventPhase( 'start', {
|
|
96
|
+
kind: 'internal_step', name: 'Internal', id: '1', parentId: 'p', details: {},
|
|
97
|
+
executionContext: { disableTrace: false }
|
|
98
|
+
} );
|
|
99
|
+
expect( localExecMock ).not.toHaveBeenCalled();
|
|
100
|
+
} );
|
|
101
|
+
|
|
90
102
|
it( 'addEventPhaseWithContext() uses storage when available', async () => {
|
|
91
103
|
process.env.OUTPUT_TRACE_LOCAL_ON = 'true';
|
|
92
104
|
storageLoadMock.mockReturnValue( {
|
|
@@ -128,23 +140,60 @@ describe( 'tracing/trace_engine', () => {
|
|
|
128
140
|
expect( localExecMock ).not.toHaveBeenCalled();
|
|
129
141
|
} );
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
133
|
-
process.env.OUTPUT_TRACE_REMOTE_ON = '1';
|
|
134
|
-
const { getDestinations } = await loadTraceEngine();
|
|
135
|
-
const result = getDestinations( { workflowId: 'w1', workflowName: 'WF', startTime: 1, disableTrace: true } );
|
|
136
|
-
expect( result ).toEqual( { local: null, remote: null } );
|
|
137
|
-
expect( localGetDestinationMock ).not.toHaveBeenCalled();
|
|
138
|
-
expect( s3GetDestinationMock ).not.toHaveBeenCalled();
|
|
139
|
-
} );
|
|
140
|
-
|
|
141
|
-
it( 'getDestinations() returns processor destinations when disableTrace is false', async () => {
|
|
142
|
-
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
143
|
-
process.env.OUTPUT_TRACE_REMOTE_ON = '0';
|
|
144
|
-
const { getDestinations } = await loadTraceEngine();
|
|
143
|
+
describe( 'getDestinations()', () => {
|
|
145
144
|
const executionContext = { workflowId: 'w1', workflowName: 'WF', startTime: 1, disableTrace: false };
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
|
|
146
|
+
it( 'returns null for both when traces are off (env vars unset)', async () => {
|
|
147
|
+
const { getDestinations } = await loadTraceEngine();
|
|
148
|
+
const result = getDestinations( executionContext );
|
|
149
|
+
expect( result ).toEqual( { local: null, remote: null } );
|
|
150
|
+
expect( localGetDestinationMock ).not.toHaveBeenCalled();
|
|
151
|
+
expect( s3GetDestinationMock ).not.toHaveBeenCalled();
|
|
152
|
+
} );
|
|
153
|
+
|
|
154
|
+
it( 'returns null for both when executionContext.disableTrace is true', async () => {
|
|
155
|
+
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
156
|
+
process.env.OUTPUT_TRACE_REMOTE_ON = '1';
|
|
157
|
+
const { getDestinations } = await loadTraceEngine();
|
|
158
|
+
const result = getDestinations( { ...executionContext, disableTrace: true } );
|
|
159
|
+
expect( result ).toEqual( { local: null, remote: null } );
|
|
160
|
+
expect( localGetDestinationMock ).not.toHaveBeenCalled();
|
|
161
|
+
expect( s3GetDestinationMock ).not.toHaveBeenCalled();
|
|
162
|
+
} );
|
|
163
|
+
|
|
164
|
+
it( 'returns both destinations when both traces are on', async () => {
|
|
165
|
+
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
166
|
+
process.env.OUTPUT_TRACE_REMOTE_ON = 'true';
|
|
167
|
+
const { getDestinations } = await loadTraceEngine();
|
|
168
|
+
const result = getDestinations( executionContext );
|
|
169
|
+
expect( result ).toEqual( {
|
|
170
|
+
local: '/local/path.json',
|
|
171
|
+
remote: 'https://bucket.s3.amazonaws.com/key.json'
|
|
172
|
+
} );
|
|
173
|
+
expect( localGetDestinationMock ).toHaveBeenCalledTimes( 1 );
|
|
174
|
+
expect( localGetDestinationMock ).toHaveBeenCalledWith( executionContext );
|
|
175
|
+
expect( s3GetDestinationMock ).toHaveBeenCalledTimes( 1 );
|
|
176
|
+
expect( s3GetDestinationMock ).toHaveBeenCalledWith( executionContext );
|
|
177
|
+
} );
|
|
178
|
+
|
|
179
|
+
it( 'returns local only when local trace on and remote off', async () => {
|
|
180
|
+
process.env.OUTPUT_TRACE_LOCAL_ON = '1';
|
|
181
|
+
process.env.OUTPUT_TRACE_REMOTE_ON = '0';
|
|
182
|
+
const { getDestinations } = await loadTraceEngine();
|
|
183
|
+
const result = getDestinations( executionContext );
|
|
184
|
+
expect( result ).toEqual( { local: '/local/path.json', remote: null } );
|
|
185
|
+
expect( localGetDestinationMock ).toHaveBeenCalledWith( executionContext );
|
|
186
|
+
expect( s3GetDestinationMock ).not.toHaveBeenCalled();
|
|
187
|
+
} );
|
|
188
|
+
|
|
189
|
+
it( 'returns remote only when local trace off and remote on', async () => {
|
|
190
|
+
process.env.OUTPUT_TRACE_LOCAL_ON = '0';
|
|
191
|
+
process.env.OUTPUT_TRACE_REMOTE_ON = 'true';
|
|
192
|
+
const { getDestinations } = await loadTraceEngine();
|
|
193
|
+
const result = getDestinations( executionContext );
|
|
194
|
+
expect( result ).toEqual( { local: null, remote: 'https://bucket.s3.amazonaws.com/key.json' } );
|
|
195
|
+
expect( localGetDestinationMock ).not.toHaveBeenCalled();
|
|
196
|
+
expect( s3GetDestinationMock ).toHaveBeenCalledWith( executionContext );
|
|
197
|
+
} );
|
|
149
198
|
} );
|
|
150
199
|
} );
|
|
@@ -2,7 +2,7 @@ import { Context } from '@temporalio/activity';
|
|
|
2
2
|
import { Storage } from '#async_storage';
|
|
3
3
|
import { addEventStart, addEventEnd, addEventError } from '#tracing';
|
|
4
4
|
import { headersToObject } from '../sandboxed_utils.js';
|
|
5
|
-
import {
|
|
5
|
+
import { LifecycleEvent, METADATA_ACCESS_SYMBOL } from '#consts';
|
|
6
6
|
import { activityHeartbeatEnabled, activityHeartbeatIntervalMs } from '../configs.js';
|
|
7
7
|
import { createChildLogger } from '#logger';
|
|
8
8
|
|
|
@@ -37,7 +37,7 @@ export class ActivityExecutionInterceptor {
|
|
|
37
37
|
const logContext = { workflowName, workflowId, stepId: activityId, stepName: activityType };
|
|
38
38
|
const traceArguments = { kind, id: activityId, parentId: workflowId, name: activityType, executionContext };
|
|
39
39
|
|
|
40
|
-
log.info(
|
|
40
|
+
log.info( `Started ${activityType} ${kind}`, { event: LifecycleEvent.START, kind, ...logContext } );
|
|
41
41
|
addEventStart( { details: input.args[0], ...traceArguments } );
|
|
42
42
|
|
|
43
43
|
const intervals = { heartbeat: null };
|
|
@@ -47,12 +47,14 @@ export class ActivityExecutionInterceptor {
|
|
|
47
47
|
|
|
48
48
|
const output = await Storage.runWithContext( async _ => next( input ), { parentId: activityId, executionContext } );
|
|
49
49
|
|
|
50
|
-
log.info(
|
|
50
|
+
log.info( `Ended ${activityType} ${kind}`, { event: LifecycleEvent.END, kind, ...logContext, durationMs: Date.now() - startDate } );
|
|
51
51
|
addEventEnd( { details: output, ...traceArguments } );
|
|
52
52
|
return output;
|
|
53
53
|
|
|
54
54
|
} catch ( error ) {
|
|
55
|
-
log.error(
|
|
55
|
+
log.error( `Error ${activityType} ${kind}: ${error.message}`, {
|
|
56
|
+
event: LifecycleEvent.ERROR, kind, ...logContext, durationMs: Date.now() - startDate, error: error.message
|
|
57
|
+
} );
|
|
56
58
|
addEventError( { details: error, ...traceArguments } );
|
|
57
59
|
throw error;
|
|
58
60
|
|
package/src/worker/sinks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LifecycleEvent,
|
|
1
|
+
import { LifecycleEvent, WORKFLOW_CATALOG } from '#consts';
|
|
2
2
|
import { addEventStart, addEventEnd, addEventError } from '#tracing';
|
|
3
3
|
import { createChildLogger } from '#logger';
|
|
4
4
|
|
|
@@ -34,11 +34,12 @@ const logWorkflowEvent = ( event, workflowInfo, error ) => {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
if ( event === LifecycleEvent.START ) {
|
|
37
|
-
log.info(
|
|
37
|
+
log.info( `Started ${workflowName} workflow`, { event, workflowName, workflowId } );
|
|
38
38
|
} else if ( event === LifecycleEvent.END ) {
|
|
39
|
-
log.info(
|
|
39
|
+
log.info( `Ended ${workflowName} workflow`, { event, workflowName, workflowId, durationMs: Date.now() - startTime.getTime() } );
|
|
40
40
|
} else if ( event === LifecycleEvent.ERROR ) {
|
|
41
|
-
log.
|
|
41
|
+
log.error( `Error ${workflowName} workflow: ${error.message}`, {
|
|
42
|
+
event,
|
|
42
43
|
workflowName,
|
|
43
44
|
workflowId,
|
|
44
45
|
durationMs: Date.now() - startTime.getTime(),
|