@orbytautomation/engine 0.2.4 → 0.4.0
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/README.md +1 -1
- package/dist/adapters/AdapterRegistry.d.ts.map +1 -1
- package/dist/adapters/AdapterRegistry.js +6 -0
- package/dist/adapters/AdapterRegistry.js.map +1 -1
- package/dist/context/VariableResolver.d.ts.map +1 -1
- package/dist/context/VariableResolver.js +7 -0
- package/dist/context/VariableResolver.js.map +1 -1
- package/dist/core/OrbytEngine.d.ts +19 -0
- package/dist/core/OrbytEngine.d.ts.map +1 -1
- package/dist/core/OrbytEngine.js +79 -3
- package/dist/core/OrbytEngine.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/errors/ErrorCodes.d.ts +205 -6
- package/dist/errors/ErrorCodes.d.ts.map +1 -1
- package/dist/errors/ErrorCodes.js +398 -5
- package/dist/errors/ErrorCodes.js.map +1 -1
- package/dist/errors/ErrorDebugger.d.ts +98 -0
- package/dist/errors/ErrorDebugger.d.ts.map +1 -0
- package/dist/errors/ErrorDebugger.js +290 -0
- package/dist/errors/ErrorDebugger.js.map +1 -0
- package/dist/errors/ErrorDetector.d.ts +148 -0
- package/dist/errors/ErrorDetector.d.ts.map +1 -0
- package/dist/errors/ErrorDetector.js +370 -0
- package/dist/errors/ErrorDetector.js.map +1 -0
- package/dist/errors/ErrorFormatter.d.ts +92 -3
- package/dist/errors/ErrorFormatter.d.ts.map +1 -1
- package/dist/errors/ErrorFormatter.js +220 -4
- package/dist/errors/ErrorFormatter.js.map +1 -1
- package/dist/errors/ErrorHandler.d.ts +259 -0
- package/dist/errors/ErrorHandler.d.ts.map +1 -0
- package/dist/errors/ErrorHandler.js +378 -0
- package/dist/errors/ErrorHandler.js.map +1 -0
- package/dist/errors/FieldRegistry.d.ts +39 -0
- package/dist/errors/FieldRegistry.d.ts.map +1 -1
- package/dist/errors/FieldRegistry.js +172 -74
- package/dist/errors/FieldRegistry.js.map +1 -1
- package/dist/errors/OrbytError.d.ts +85 -3
- package/dist/errors/OrbytError.d.ts.map +1 -1
- package/dist/errors/OrbytError.js +151 -4
- package/dist/errors/OrbytError.js.map +1 -1
- package/dist/errors/SchedulerError.d.ts +93 -1
- package/dist/errors/SchedulerError.d.ts.map +1 -1
- package/dist/errors/SchedulerError.js +145 -1
- package/dist/errors/SchedulerError.js.map +1 -1
- package/dist/errors/SecurityErrors.d.ts +94 -12
- package/dist/errors/SecurityErrors.d.ts.map +1 -1
- package/dist/errors/SecurityErrors.js +162 -18
- package/dist/errors/SecurityErrors.js.map +1 -1
- package/dist/errors/StepError.d.ts +111 -1
- package/dist/errors/StepError.d.ts.map +1 -1
- package/dist/errors/StepError.js +182 -1
- package/dist/errors/StepError.js.map +1 -1
- package/dist/errors/WorkflowError.d.ts +139 -2
- package/dist/errors/WorkflowError.d.ts.map +1 -1
- package/dist/errors/WorkflowError.js +264 -22
- package/dist/errors/WorkflowError.js.map +1 -1
- package/dist/errors/index.d.ts +5 -1
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +7 -4
- package/dist/errors/index.js.map +1 -1
- package/dist/execution/ExecutionEngine.d.ts.map +1 -1
- package/dist/execution/ExecutionEngine.js +36 -6
- package/dist/execution/ExecutionEngine.js.map +1 -1
- package/dist/execution/ExecutionPlan.d.ts.map +1 -1
- package/dist/execution/ExecutionPlan.js +21 -1
- package/dist/execution/ExecutionPlan.js.map +1 -1
- package/dist/execution/IntentAnalyzer.d.ts.map +1 -1
- package/dist/execution/IntentAnalyzer.js +20 -0
- package/dist/execution/IntentAnalyzer.js.map +1 -1
- package/dist/execution/StepExecutor.d.ts.map +1 -1
- package/dist/execution/StepExecutor.js +109 -29
- package/dist/execution/StepExecutor.js.map +1 -1
- package/dist/execution/WorkflowExecutor.d.ts.map +1 -1
- package/dist/execution/WorkflowExecutor.js +31 -0
- package/dist/execution/WorkflowExecutor.js.map +1 -1
- package/dist/explanation/ExplanationGenerator.d.ts +105 -0
- package/dist/explanation/ExplanationGenerator.d.ts.map +1 -0
- package/dist/explanation/ExplanationGenerator.js +814 -0
- package/dist/explanation/ExplanationGenerator.js.map +1 -0
- package/dist/explanation/ExplanationLogger.d.ts +50 -0
- package/dist/explanation/ExplanationLogger.d.ts.map +1 -0
- package/dist/explanation/ExplanationLogger.js +284 -0
- package/dist/explanation/ExplanationLogger.js.map +1 -0
- package/dist/explanation/ExplanationTypes.d.ts +252 -0
- package/dist/explanation/ExplanationTypes.d.ts.map +1 -0
- package/dist/explanation/ExplanationTypes.js +10 -0
- package/dist/explanation/ExplanationTypes.js.map +1 -0
- package/dist/explanation/index.d.ts +12 -0
- package/dist/explanation/index.d.ts.map +1 -0
- package/dist/explanation/index.js +11 -0
- package/dist/explanation/index.js.map +1 -0
- package/dist/hooks/HookManager.d.ts.map +1 -1
- package/dist/hooks/HookManager.js +8 -0
- package/dist/hooks/HookManager.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/ShutdownManager.d.ts.map +1 -1
- package/dist/lifecycle/ShutdownManager.js +22 -9
- package/dist/lifecycle/ShutdownManager.js.map +1 -1
- package/dist/lifecycle/StartupManager.d.ts.map +1 -1
- package/dist/lifecycle/StartupManager.js +16 -5
- package/dist/lifecycle/StartupManager.js.map +1 -1
- package/dist/loader/WorkflowLoader.d.ts +83 -21
- package/dist/loader/WorkflowLoader.d.ts.map +1 -1
- package/dist/loader/WorkflowLoader.js +169 -55
- package/dist/loader/WorkflowLoader.js.map +1 -1
- package/dist/logging/EngineLogger.d.ts +492 -0
- package/dist/logging/EngineLogger.d.ts.map +1 -0
- package/dist/logging/EngineLogger.js +1170 -0
- package/dist/logging/EngineLogger.js.map +1 -0
- package/dist/logging/LoggerManager.d.ts +49 -0
- package/dist/logging/LoggerManager.d.ts.map +1 -0
- package/dist/logging/LoggerManager.js +94 -0
- package/dist/logging/LoggerManager.js.map +1 -0
- package/dist/logging/index.d.ts +2 -1
- package/dist/logging/index.d.ts.map +1 -1
- package/dist/logging/index.js +2 -3
- package/dist/logging/index.js.map +1 -1
- package/dist/parser/SchemaValidator.d.ts.map +1 -1
- package/dist/parser/SchemaValidator.js +8 -1
- package/dist/parser/SchemaValidator.js.map +1 -1
- package/dist/parser/StepParser.d.ts +6 -1
- package/dist/parser/StepParser.d.ts.map +1 -1
- package/dist/parser/StepParser.js +14 -1
- package/dist/parser/StepParser.js.map +1 -1
- package/dist/parser/WorkflowParser.d.ts.map +1 -1
- package/dist/parser/WorkflowParser.js +53 -28
- package/dist/parser/WorkflowParser.js.map +1 -1
- package/dist/scheduling/ScheduleParser.d.ts.map +1 -1
- package/dist/scheduling/ScheduleParser.js +7 -0
- package/dist/scheduling/ScheduleParser.js.map +1 -1
- package/dist/scheduling/Scheduler.d.ts.map +1 -1
- package/dist/scheduling/Scheduler.js +13 -0
- package/dist/scheduling/Scheduler.js.map +1 -1
- package/dist/types/log-types.d.ts +105 -0
- package/dist/types/log-types.d.ts.map +1 -0
- package/dist/types/log-types.js +42 -0
- package/dist/types/log-types.js.map +1 -0
- package/package.json +1 -1
- package/dist/core/EngineLogger.d.ts +0 -182
- package/dist/core/EngineLogger.d.ts.map +0 -1
- package/dist/core/EngineLogger.js +0 -293
- package/dist/core/EngineLogger.js.map +0 -1
- package/dist/logging/LogLevel.d.ts +0 -2
- package/dist/logging/LogLevel.d.ts.map +0 -1
- package/dist/logging/LogLevel.js +0 -2
- package/dist/logging/LogLevel.js.map +0 -1
- package/dist/logging/Logger.d.ts +0 -2
- package/dist/logging/Logger.d.ts.map +0 -1
- package/dist/logging/Logger.js +0 -2
- package/dist/logging/Logger.js.map +0 -1
|
@@ -0,0 +1,1170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine Logger
|
|
3
|
+
*
|
|
4
|
+
* Provides structured logging for the Orbyt Engine using ecosystem-core utilities.
|
|
5
|
+
* Supports multiple output formats and log levels with proper filtering.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Severity-based log level filtering using LogLevelSeverity
|
|
9
|
+
* - Multiple output formats (pretty, text, json, structured)
|
|
10
|
+
* - Color support with ANSI codes
|
|
11
|
+
* - Engine-generated timestamps (consistent across CLI, API, web dashboards)
|
|
12
|
+
* - Context and error tracking
|
|
13
|
+
* - Performance measurement with automatic severity adjustment
|
|
14
|
+
* - Efficient level comparison using numeric severity
|
|
15
|
+
*
|
|
16
|
+
* Timestamps are generated by the engine to ensure consistency across:
|
|
17
|
+
* - CLI output
|
|
18
|
+
* - API responses
|
|
19
|
+
* - Web dashboard logs
|
|
20
|
+
* - Monitoring systems
|
|
21
|
+
* - Audit trails
|
|
22
|
+
*
|
|
23
|
+
* @module core
|
|
24
|
+
*/
|
|
25
|
+
import { LogLevel, LogLevelSeverity, formatLog, createLogEntry, shouldLog, formatTimestamp, } from '@dev-ecosystem/core';
|
|
26
|
+
import { EngineLogType } from '../types/log-types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Re-export formatTimestamp for external use
|
|
29
|
+
* Allows other parts of the system to format timestamps consistently
|
|
30
|
+
*/
|
|
31
|
+
export { formatTimestamp };
|
|
32
|
+
/**
|
|
33
|
+
* Engine Logger
|
|
34
|
+
*
|
|
35
|
+
* Wraps ecosystem-core logging utilities with engine-specific configuration.
|
|
36
|
+
*/
|
|
37
|
+
export class EngineLogger {
|
|
38
|
+
config;
|
|
39
|
+
formatOptions;
|
|
40
|
+
eventListeners;
|
|
41
|
+
logBuffer; // Structured JSON log buffer
|
|
42
|
+
maxBufferSize = 10000; // Prevent memory leaks
|
|
43
|
+
constructor(config) {
|
|
44
|
+
this.config = {
|
|
45
|
+
level: config.level,
|
|
46
|
+
format: config.format || 'text',
|
|
47
|
+
colors: config.colors ?? true,
|
|
48
|
+
timestamp: config.timestamp ?? true,
|
|
49
|
+
source: config.source || 'Orbyt',
|
|
50
|
+
structuredEvents: config.structuredEvents ?? true, // Default to true for JSON collection
|
|
51
|
+
};
|
|
52
|
+
this.formatOptions = {
|
|
53
|
+
format: this.config.format,
|
|
54
|
+
colors: this.config.colors,
|
|
55
|
+
timestamp: this.config.timestamp,
|
|
56
|
+
includeSource: true,
|
|
57
|
+
};
|
|
58
|
+
this.eventListeners = new Map();
|
|
59
|
+
this.logBuffer = [];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Log a debug message
|
|
63
|
+
*/
|
|
64
|
+
debug(message, context) {
|
|
65
|
+
this.log(LogLevel.DEBUG, message, context);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log an info message
|
|
69
|
+
*/
|
|
70
|
+
info(message, context) {
|
|
71
|
+
this.log(LogLevel.INFO, message, context);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Log a warning message
|
|
75
|
+
*/
|
|
76
|
+
warn(message, context) {
|
|
77
|
+
this.log(LogLevel.WARN, message, context);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Log an error message
|
|
81
|
+
*/
|
|
82
|
+
error(message, error, context) {
|
|
83
|
+
this.log(LogLevel.ERROR, message, context, error);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Log a fatal error message
|
|
87
|
+
*/
|
|
88
|
+
fatal(message, error, context) {
|
|
89
|
+
this.log(LogLevel.FATAL, message, context, error);
|
|
90
|
+
}
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// WORKFLOW LIFECYCLE LOGGING
|
|
93
|
+
// ============================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Log workflow started event
|
|
96
|
+
*/
|
|
97
|
+
workflowStarted(workflowName, context) {
|
|
98
|
+
this.logEvent({
|
|
99
|
+
type: EngineLogType.WORKFLOW_STARTED,
|
|
100
|
+
timestamp: new Date(),
|
|
101
|
+
message: `Workflow "${workflowName}" started`,
|
|
102
|
+
context,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Log workflow completed event
|
|
107
|
+
*/
|
|
108
|
+
workflowCompleted(workflowName, duration, context) {
|
|
109
|
+
this.logEvent({
|
|
110
|
+
type: EngineLogType.WORKFLOW_COMPLETED,
|
|
111
|
+
timestamp: new Date(),
|
|
112
|
+
message: `Workflow "${workflowName}" completed successfully`,
|
|
113
|
+
context,
|
|
114
|
+
metrics: { duration },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Log workflow failed event
|
|
119
|
+
*/
|
|
120
|
+
workflowFailed(workflowName, error, duration, context) {
|
|
121
|
+
this.logEvent({
|
|
122
|
+
type: EngineLogType.WORKFLOW_FAILED,
|
|
123
|
+
timestamp: new Date(),
|
|
124
|
+
message: `Workflow "${workflowName}" failed: ${error.message}`,
|
|
125
|
+
context,
|
|
126
|
+
error,
|
|
127
|
+
metrics: { duration },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Log workflow validation event
|
|
132
|
+
*/
|
|
133
|
+
workflowValidation(workflowName, isValid, errors) {
|
|
134
|
+
this.logEvent({
|
|
135
|
+
type: EngineLogType.WORKFLOW_VALIDATION,
|
|
136
|
+
timestamp: new Date(),
|
|
137
|
+
message: `Workflow "${workflowName}" validation: ${isValid ? 'PASSED' : 'FAILED'}`,
|
|
138
|
+
context: errors ? { errors } : undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// STEP LIFECYCLE LOGGING
|
|
143
|
+
// ============================================================================
|
|
144
|
+
/**
|
|
145
|
+
* Log step started event
|
|
146
|
+
*/
|
|
147
|
+
stepStarted(stepId, stepName, context) {
|
|
148
|
+
this.logEvent({
|
|
149
|
+
type: EngineLogType.STEP_STARTED,
|
|
150
|
+
timestamp: new Date(),
|
|
151
|
+
message: `Step "${stepName}" (${stepId}) started`,
|
|
152
|
+
context,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Log step completed event
|
|
157
|
+
*/
|
|
158
|
+
stepCompleted(stepId, stepName, duration, context) {
|
|
159
|
+
this.logEvent({
|
|
160
|
+
type: EngineLogType.STEP_COMPLETED,
|
|
161
|
+
timestamp: new Date(),
|
|
162
|
+
message: `Step "${stepName}" (${stepId}) completed`,
|
|
163
|
+
context,
|
|
164
|
+
metrics: { duration },
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Log step failed event
|
|
169
|
+
*/
|
|
170
|
+
stepFailed(stepId, stepName, error, context) {
|
|
171
|
+
this.logEvent({
|
|
172
|
+
type: EngineLogType.STEP_FAILED,
|
|
173
|
+
timestamp: new Date(),
|
|
174
|
+
message: `Step "${stepName}" (${stepId}) failed: ${error.message}`,
|
|
175
|
+
context,
|
|
176
|
+
error,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Log step retry event
|
|
181
|
+
*/
|
|
182
|
+
stepRetry(stepId, stepName, attempt, maxAttempts) {
|
|
183
|
+
this.logEvent({
|
|
184
|
+
type: EngineLogType.STEP_RETRY,
|
|
185
|
+
timestamp: new Date(),
|
|
186
|
+
message: `Step "${stepName}" (${stepId}) retry ${attempt}/${maxAttempts}`,
|
|
187
|
+
context: { attempt, maxAttempts },
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Log step timeout event
|
|
192
|
+
*/
|
|
193
|
+
stepTimeout(stepId, stepName, timeout) {
|
|
194
|
+
this.logEvent({
|
|
195
|
+
type: EngineLogType.STEP_TIMEOUT,
|
|
196
|
+
timestamp: new Date(),
|
|
197
|
+
message: `Step "${stepName}" (${stepId}) timed out after ${timeout}ms`,
|
|
198
|
+
context: { timeout },
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// ============================================================================
|
|
202
|
+
// EXPLANATION LOGGING
|
|
203
|
+
// ============================================================================
|
|
204
|
+
/**
|
|
205
|
+
* Log explanation generated event
|
|
206
|
+
*/
|
|
207
|
+
explanationGenerated(workflowName, stepCount, strategy) {
|
|
208
|
+
this.logEvent({
|
|
209
|
+
type: EngineLogType.EXPLANATION_GENERATED,
|
|
210
|
+
timestamp: new Date(),
|
|
211
|
+
message: `Explanation generated for "${workflowName}" (${stepCount} steps, ${strategy} strategy)`,
|
|
212
|
+
context: { workflowName, stepCount, strategy },
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Log circular dependencies detected
|
|
217
|
+
*/
|
|
218
|
+
explanationCycles(workflowName, cycles) {
|
|
219
|
+
this.logEvent({
|
|
220
|
+
type: EngineLogType.EXPLANATION_CYCLES,
|
|
221
|
+
timestamp: new Date(),
|
|
222
|
+
message: `Circular dependencies detected in "${workflowName}"`,
|
|
223
|
+
context: { cycles },
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// ADAPTER & PLUGIN LOGGING
|
|
228
|
+
// ============================================================================
|
|
229
|
+
/**
|
|
230
|
+
* Log adapter loaded event
|
|
231
|
+
*/
|
|
232
|
+
adapterLoaded(adapterName, version) {
|
|
233
|
+
this.logEvent({
|
|
234
|
+
type: EngineLogType.ADAPTER_LOADED,
|
|
235
|
+
timestamp: new Date(),
|
|
236
|
+
message: `Adapter "${adapterName}" loaded${version ? ` (v${version})` : ''}`,
|
|
237
|
+
context: { adapterName, version },
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Log adapter failed event
|
|
242
|
+
*/
|
|
243
|
+
adapterFailed(adapterName, error) {
|
|
244
|
+
this.logEvent({
|
|
245
|
+
type: EngineLogType.ADAPTER_FAILED,
|
|
246
|
+
timestamp: new Date(),
|
|
247
|
+
message: `Adapter "${adapterName}" failed: ${error.message}`,
|
|
248
|
+
context: { adapterName },
|
|
249
|
+
error,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Log plugin installed event
|
|
254
|
+
*/
|
|
255
|
+
pluginInstalled(pluginName, source) {
|
|
256
|
+
this.logEvent({
|
|
257
|
+
type: EngineLogType.PLUGIN_INSTALLED,
|
|
258
|
+
timestamp: new Date(),
|
|
259
|
+
message: `Plugin "${pluginName}" installed from ${source}`,
|
|
260
|
+
context: { pluginName, source },
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Log plugin verified event
|
|
265
|
+
*/
|
|
266
|
+
pluginVerified(pluginName, verified) {
|
|
267
|
+
this.logEvent({
|
|
268
|
+
type: EngineLogType.PLUGIN_VERIFIED,
|
|
269
|
+
timestamp: new Date(),
|
|
270
|
+
message: `Plugin "${pluginName}" verification: ${verified ? 'PASSED' : 'FAILED'}`,
|
|
271
|
+
context: { pluginName, verified },
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// ============================================================================
|
|
275
|
+
// ERROR & DEBUG LOGGING
|
|
276
|
+
// ============================================================================
|
|
277
|
+
/**
|
|
278
|
+
* Log error detected event
|
|
279
|
+
*/
|
|
280
|
+
errorDetected(error, context) {
|
|
281
|
+
this.logEvent({
|
|
282
|
+
type: EngineLogType.ERROR_DETECTED,
|
|
283
|
+
timestamp: new Date(),
|
|
284
|
+
message: `Error detected: ${error.message}`,
|
|
285
|
+
context,
|
|
286
|
+
error,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Log error debugged event (with debugging info)
|
|
291
|
+
*/
|
|
292
|
+
errorDebugged(error, debugInfo) {
|
|
293
|
+
this.logEvent({
|
|
294
|
+
type: EngineLogType.ERROR_DEBUGGED,
|
|
295
|
+
timestamp: new Date(),
|
|
296
|
+
message: `Error debugged: ${error.message}`,
|
|
297
|
+
context: debugInfo,
|
|
298
|
+
error,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Log validation error event
|
|
303
|
+
*/
|
|
304
|
+
validationError(message, errors) {
|
|
305
|
+
this.logEvent({
|
|
306
|
+
type: EngineLogType.VALIDATION_ERROR,
|
|
307
|
+
timestamp: new Date(),
|
|
308
|
+
message,
|
|
309
|
+
context: { errors },
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
// ============================================================================
|
|
313
|
+
// PERFORMANCE LOGGING
|
|
314
|
+
// ============================================================================
|
|
315
|
+
/**
|
|
316
|
+
* Log performance metric
|
|
317
|
+
*/
|
|
318
|
+
performanceMetric(label, metrics) {
|
|
319
|
+
this.logEvent({
|
|
320
|
+
type: EngineLogType.PERFORMANCE_METRIC,
|
|
321
|
+
timestamp: new Date(),
|
|
322
|
+
message: `Performance: ${label}`,
|
|
323
|
+
metrics,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Log execution time
|
|
328
|
+
*/
|
|
329
|
+
executionTime(label, duration, context) {
|
|
330
|
+
this.logEvent({
|
|
331
|
+
type: EngineLogType.EXECUTION_TIME,
|
|
332
|
+
timestamp: new Date(),
|
|
333
|
+
message: `${label}: ${duration}ms`,
|
|
334
|
+
context,
|
|
335
|
+
metrics: { duration },
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
// ============================================================================
|
|
339
|
+
// FIELD-LEVEL EXECUTION LOGGING (Dynamic Explanation)
|
|
340
|
+
// ============================================================================
|
|
341
|
+
/**
|
|
342
|
+
* Log field execution - captures every field that gets executed
|
|
343
|
+
* This enables dynamic explanation generation from runtime logs
|
|
344
|
+
*/
|
|
345
|
+
fieldExecution(type, field, value, context) {
|
|
346
|
+
// Filter out internal fields (starting with _)
|
|
347
|
+
if (field.startsWith('_'))
|
|
348
|
+
return;
|
|
349
|
+
this.debug(`[Field] ${type}.${field} = ${this.formatValue(value)}`, {
|
|
350
|
+
fieldType: type,
|
|
351
|
+
fieldName: field,
|
|
352
|
+
value: this.sanitizeValue(value),
|
|
353
|
+
...context,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Log input processing
|
|
358
|
+
*/
|
|
359
|
+
inputProcessed(inputName, value, source) {
|
|
360
|
+
this.debug(`[Input] ${inputName} received from ${source}`, {
|
|
361
|
+
input: inputName,
|
|
362
|
+
source,
|
|
363
|
+
value: this.sanitizeValue(value),
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Log output generation
|
|
368
|
+
*/
|
|
369
|
+
outputGenerated(outputName, value, step) {
|
|
370
|
+
this.debug(`[Output] ${outputName} generated${step ? ` by ${step}` : ''}`, {
|
|
371
|
+
output: outputName,
|
|
372
|
+
step,
|
|
373
|
+
value: this.sanitizeValue(value),
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Log context variable access
|
|
378
|
+
*/
|
|
379
|
+
contextAccessed(variable, value, step) {
|
|
380
|
+
this.debug(`[Context] ${variable} accessed by ${step}`, {
|
|
381
|
+
variable,
|
|
382
|
+
step,
|
|
383
|
+
value: this.sanitizeValue(value),
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Log secret access (without exposing values)
|
|
388
|
+
*/
|
|
389
|
+
secretAccessed(secretKey, step) {
|
|
390
|
+
this.debug(`[Secret] ${secretKey} accessed by ${step}`, {
|
|
391
|
+
secretKey,
|
|
392
|
+
step,
|
|
393
|
+
exposed: false, // Never log secret values
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Log variable resolution
|
|
398
|
+
*/
|
|
399
|
+
variableResolved(variable, resolvedValue, context) {
|
|
400
|
+
this.debug(`[Variable] ${variable} resolved`, {
|
|
401
|
+
variable,
|
|
402
|
+
resolved: this.sanitizeValue(resolvedValue),
|
|
403
|
+
...context,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Log adapter action execution
|
|
408
|
+
*/
|
|
409
|
+
adapterActionExecuted(adapter, action, duration, success) {
|
|
410
|
+
const message = `[Adapter] ${adapter}.${action} ${success ? 'completed' : 'failed'} in ${duration}ms`;
|
|
411
|
+
const context = { adapter, action, duration, success };
|
|
412
|
+
if (success) {
|
|
413
|
+
this.info(message, context);
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
this.error(message, undefined, context);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// ============================================================================
|
|
420
|
+
// PARSING & VALIDATION LOGGING
|
|
421
|
+
// ============================================================================
|
|
422
|
+
/**
|
|
423
|
+
* Log parsing start
|
|
424
|
+
*/
|
|
425
|
+
parsingStarted(source, format) {
|
|
426
|
+
this.debug(`[Parser] Parsing ${format} from ${source}`, {
|
|
427
|
+
source,
|
|
428
|
+
format,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Log parsing success
|
|
433
|
+
*/
|
|
434
|
+
parsingCompleted(source, duration, stats) {
|
|
435
|
+
this.info(`[Parser] Parsed successfully in ${duration}ms`, {
|
|
436
|
+
source,
|
|
437
|
+
duration,
|
|
438
|
+
...stats,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Log parsing error
|
|
443
|
+
*/
|
|
444
|
+
parsingFailed(source, error, context) {
|
|
445
|
+
this.error(`[Parser] Parsing failed: ${error.message}`, error, {
|
|
446
|
+
source,
|
|
447
|
+
...context,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Log validation start
|
|
452
|
+
*/
|
|
453
|
+
validationStarted(target, type) {
|
|
454
|
+
this.debug(`[Validator] Validating ${type}: ${target}`, {
|
|
455
|
+
target,
|
|
456
|
+
type,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Log validation success
|
|
461
|
+
*/
|
|
462
|
+
validationPassed(target, type, duration) {
|
|
463
|
+
this.info(`[Validator] Validation passed: ${target}`, {
|
|
464
|
+
target,
|
|
465
|
+
type,
|
|
466
|
+
duration,
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Log validation failure
|
|
471
|
+
*/
|
|
472
|
+
validationFailed(target, type, errors) {
|
|
473
|
+
this.error(`[Validator] Validation failed: ${target}`, undefined, {
|
|
474
|
+
target,
|
|
475
|
+
type,
|
|
476
|
+
errors,
|
|
477
|
+
errorCount: errors.length,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
// ============================================================================
|
|
481
|
+
// ERROR DETECTION & DEBUGGING LOGGING
|
|
482
|
+
// ============================================================================
|
|
483
|
+
/**
|
|
484
|
+
* Log error enrichment (when ErrorDetector adds debugging info)
|
|
485
|
+
*/
|
|
486
|
+
errorEnriched(error, debugInfo) {
|
|
487
|
+
this.debug(`[ErrorDetector] Error enriched with debugging info`, {
|
|
488
|
+
errorType: error.name,
|
|
489
|
+
errorMessage: error.message,
|
|
490
|
+
...debugInfo,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Log error debugging output
|
|
495
|
+
*/
|
|
496
|
+
errorDebugOutput(error, explanation, fixSteps) {
|
|
497
|
+
this.info(`[ErrorDebugger] Generated debugging output for ${error.name}`, {
|
|
498
|
+
errorType: error.name,
|
|
499
|
+
explanation,
|
|
500
|
+
fixSteps,
|
|
501
|
+
stepCount: fixSteps.length,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
// ============================================================================
|
|
505
|
+
// EXECUTION PHASE LOGGING
|
|
506
|
+
// ============================================================================
|
|
507
|
+
/**
|
|
508
|
+
* Log execution phase start
|
|
509
|
+
*/
|
|
510
|
+
phaseStarted(phase, stepIds) {
|
|
511
|
+
this.info(`[Execution] Phase ${phase} started with ${stepIds.length} step(s)`, {
|
|
512
|
+
phase,
|
|
513
|
+
stepIds,
|
|
514
|
+
stepCount: stepIds.length,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Log execution phase completion
|
|
519
|
+
*/
|
|
520
|
+
phaseCompleted(phase, duration, successCount, failureCount) {
|
|
521
|
+
this.info(`[Execution] Phase ${phase} completed in ${duration}ms`, {
|
|
522
|
+
phase,
|
|
523
|
+
duration,
|
|
524
|
+
successCount,
|
|
525
|
+
failureCount,
|
|
526
|
+
totalSteps: successCount + failureCount,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
// ============================================================================
|
|
530
|
+
// UTILITY METHODS
|
|
531
|
+
// ============================================================================
|
|
532
|
+
/**
|
|
533
|
+
* Format value for logging (truncate large values)
|
|
534
|
+
*/
|
|
535
|
+
formatValue(value) {
|
|
536
|
+
if (value === null)
|
|
537
|
+
return 'null';
|
|
538
|
+
if (value === undefined)
|
|
539
|
+
return 'undefined';
|
|
540
|
+
if (typeof value === 'string') {
|
|
541
|
+
return value.length > 100 ? `${value.substring(0, 97)}...` : value;
|
|
542
|
+
}
|
|
543
|
+
if (typeof value === 'object') {
|
|
544
|
+
const str = JSON.stringify(value);
|
|
545
|
+
return str.length > 200 ? `${str.substring(0, 197)}...` : str;
|
|
546
|
+
}
|
|
547
|
+
return String(value);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Sanitize value for logging (remove sensitive data)
|
|
551
|
+
*/
|
|
552
|
+
sanitizeValue(value) {
|
|
553
|
+
if (value === null || value === undefined)
|
|
554
|
+
return value;
|
|
555
|
+
// For objects, recursively sanitize
|
|
556
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
557
|
+
const sanitized = {};
|
|
558
|
+
for (const [key, val] of Object.entries(value)) {
|
|
559
|
+
// Skip internal fields
|
|
560
|
+
if (key.startsWith('_'))
|
|
561
|
+
continue;
|
|
562
|
+
// Mask sensitive fields
|
|
563
|
+
if (this.isSensitiveField(key)) {
|
|
564
|
+
sanitized[key] = '***REDACTED***';
|
|
565
|
+
}
|
|
566
|
+
else if (typeof val === 'object') {
|
|
567
|
+
sanitized[key] = this.sanitizeValue(val);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
sanitized[key] = val;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return sanitized;
|
|
574
|
+
}
|
|
575
|
+
return value;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Check if field name suggests sensitive data
|
|
579
|
+
*/
|
|
580
|
+
isSensitiveField(fieldName) {
|
|
581
|
+
const sensitivePatterns = [
|
|
582
|
+
'password', 'secret', 'token', 'key', 'credential',
|
|
583
|
+
'apikey', 'api_key', 'auth', 'private',
|
|
584
|
+
];
|
|
585
|
+
const lowerField = fieldName.toLowerCase();
|
|
586
|
+
return sensitivePatterns.some(pattern => lowerField.includes(pattern));
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Log with a custom level
|
|
590
|
+
*/
|
|
591
|
+
logWithLevel(level, message, context) {
|
|
592
|
+
this.log(level, message, context);
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Log only if severity meets minimum threshold
|
|
596
|
+
*/
|
|
597
|
+
logIfSeverity(minSeverity, level, message, context) {
|
|
598
|
+
if (LogLevelSeverity[level] >= minSeverity) {
|
|
599
|
+
this.log(level, message, context);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Measure and log execution time with appropriate log level based on duration
|
|
604
|
+
*/
|
|
605
|
+
async measureExecution(label, fn, thresholds) {
|
|
606
|
+
const start = Date.now();
|
|
607
|
+
try {
|
|
608
|
+
const result = await fn();
|
|
609
|
+
const duration = Date.now() - start;
|
|
610
|
+
// Choose log level based on duration thresholds
|
|
611
|
+
let level = LogLevel.DEBUG;
|
|
612
|
+
if (thresholds?.error && duration > thresholds.error) {
|
|
613
|
+
level = LogLevel.ERROR;
|
|
614
|
+
}
|
|
615
|
+
else if (thresholds?.warn && duration > thresholds.warn) {
|
|
616
|
+
level = LogLevel.WARN;
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
level = LogLevel.INFO;
|
|
620
|
+
}
|
|
621
|
+
this.log(level, `${label} completed`, { duration: `${duration}ms` });
|
|
622
|
+
return result;
|
|
623
|
+
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
const duration = Date.now() - start;
|
|
626
|
+
this.log(LogLevel.ERROR, `${label} failed`, { duration: `${duration}ms` }, error instanceof Error ? error : new Error(String(error)));
|
|
627
|
+
throw error;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Log a structured engine event
|
|
632
|
+
*/
|
|
633
|
+
logEvent(event) {
|
|
634
|
+
// Add to JSON buffer (always, regardless of log level)
|
|
635
|
+
this.addToBuffer(event);
|
|
636
|
+
// Emit event to listeners if structured events enabled
|
|
637
|
+
if (this.config.structuredEvents) {
|
|
638
|
+
this.emitEvent(event);
|
|
639
|
+
}
|
|
640
|
+
// Determine log level based on event type
|
|
641
|
+
const level = this.getLogLevelForEventType(event.type);
|
|
642
|
+
// Check if this level should be logged
|
|
643
|
+
if (!this.shouldLogLevel(level)) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
// Build context with metrics if present
|
|
647
|
+
const fullContext = {
|
|
648
|
+
...event.context,
|
|
649
|
+
...(event.metrics && { metrics: event.metrics }),
|
|
650
|
+
};
|
|
651
|
+
// Log through standard log method
|
|
652
|
+
this.log(level, event.message, fullContext, event.error);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Get appropriate log level for event type
|
|
656
|
+
*/
|
|
657
|
+
getLogLevelForEventType(type) {
|
|
658
|
+
// Error events
|
|
659
|
+
if (type.includes('failed') || type.includes('error') || type.includes('timeout')) {
|
|
660
|
+
return LogLevel.ERROR;
|
|
661
|
+
}
|
|
662
|
+
// Warning events
|
|
663
|
+
if (type.includes('retry') || type.includes('cycles') || type === EngineLogType.WARNING) {
|
|
664
|
+
return LogLevel.WARN;
|
|
665
|
+
}
|
|
666
|
+
// Debug events
|
|
667
|
+
if (type === EngineLogType.DEBUG || type.includes('debug')) {
|
|
668
|
+
return LogLevel.DEBUG;
|
|
669
|
+
}
|
|
670
|
+
// Default to INFO
|
|
671
|
+
return LogLevel.INFO;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Emit event to registered listeners
|
|
675
|
+
*/
|
|
676
|
+
emitEvent(event) {
|
|
677
|
+
const listeners = this.eventListeners.get(event.type) || [];
|
|
678
|
+
for (const listener of listeners) {
|
|
679
|
+
try {
|
|
680
|
+
listener(event);
|
|
681
|
+
}
|
|
682
|
+
catch (error) {
|
|
683
|
+
// Don't let listener errors crash the logger
|
|
684
|
+
console.error('Error in log event listener:', error);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
// Also emit to wildcard listeners
|
|
688
|
+
const wildcardListeners = this.eventListeners.get(EngineLogType.INFO) || [];
|
|
689
|
+
for (const listener of wildcardListeners) {
|
|
690
|
+
try {
|
|
691
|
+
listener(event);
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
console.error('Error in wildcard log event listener:', error);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Subscribe to specific log event types
|
|
700
|
+
*/
|
|
701
|
+
on(type, listener) {
|
|
702
|
+
if (!this.eventListeners.has(type)) {
|
|
703
|
+
this.eventListeners.set(type, []);
|
|
704
|
+
}
|
|
705
|
+
this.eventListeners.get(type).push(listener);
|
|
706
|
+
// Return unsubscribe function
|
|
707
|
+
return () => {
|
|
708
|
+
const listeners = this.eventListeners.get(type);
|
|
709
|
+
if (listeners) {
|
|
710
|
+
const index = listeners.indexOf(listener);
|
|
711
|
+
if (index > -1) {
|
|
712
|
+
listeners.splice(index, 1);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Internal log method
|
|
719
|
+
*/
|
|
720
|
+
log(level, message, context, error) {
|
|
721
|
+
// Check if this level should be logged (using severity for better performance)
|
|
722
|
+
if (!this.shouldLogLevel(level)) {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
// Create log entry
|
|
726
|
+
const entry = createLogEntry(level, message, {
|
|
727
|
+
source: this.config.source,
|
|
728
|
+
context,
|
|
729
|
+
error,
|
|
730
|
+
});
|
|
731
|
+
// Add basic logs to buffer as well (for comprehensive JSON output)
|
|
732
|
+
this.addToBuffer({
|
|
733
|
+
type: this.mapLogLevelToEventType(level),
|
|
734
|
+
timestamp: new Date(),
|
|
735
|
+
message,
|
|
736
|
+
context,
|
|
737
|
+
error,
|
|
738
|
+
});
|
|
739
|
+
// Format and output
|
|
740
|
+
const formatted = formatLog(entry, this.formatOptions);
|
|
741
|
+
console.log(formatted);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Map LogLevel to EngineLogType
|
|
745
|
+
*/
|
|
746
|
+
mapLogLevelToEventType(level) {
|
|
747
|
+
switch (level) {
|
|
748
|
+
case LogLevel.DEBUG: return EngineLogType.DEBUG;
|
|
749
|
+
case LogLevel.INFO: return EngineLogType.INFO;
|
|
750
|
+
case LogLevel.WARN: return EngineLogType.WARNING;
|
|
751
|
+
case LogLevel.ERROR:
|
|
752
|
+
case LogLevel.FATAL: return EngineLogType.ERROR;
|
|
753
|
+
default: return EngineLogType.INFO;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Check if a level should be logged using severity comparison
|
|
758
|
+
*/
|
|
759
|
+
shouldLogLevel(level) {
|
|
760
|
+
return LogLevelSeverity[level] >= LogLevelSeverity[this.config.level];
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Check if a level is more severe than another
|
|
764
|
+
*/
|
|
765
|
+
isMoreSevere(level, compareWith) {
|
|
766
|
+
return LogLevelSeverity[level] > LogLevelSeverity[compareWith];
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Get severity difference between two levels
|
|
770
|
+
*/
|
|
771
|
+
getSeverityDiff(level1, level2) {
|
|
772
|
+
return LogLevelSeverity[level1] - LogLevelSeverity[level2];
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Get the numeric severity of the current log level
|
|
776
|
+
*/
|
|
777
|
+
getCurrentSeverity() {
|
|
778
|
+
return LogLevelSeverity[this.config.level];
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Get the numeric severity of a log level
|
|
782
|
+
*/
|
|
783
|
+
getSeverity(level) {
|
|
784
|
+
return LogLevelSeverity[level];
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Update logger configuration
|
|
788
|
+
*/
|
|
789
|
+
setLevel(level) {
|
|
790
|
+
this.config.level = level;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Set level by severity (0-4)
|
|
794
|
+
*/
|
|
795
|
+
setLevelBySeverity(severity) {
|
|
796
|
+
const levels = Object.entries(LogLevelSeverity)
|
|
797
|
+
.find(([_, sev]) => sev === severity);
|
|
798
|
+
if (levels) {
|
|
799
|
+
this.config.level = levels[0];
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Update colors setting
|
|
804
|
+
*/
|
|
805
|
+
setColors(enabled) {
|
|
806
|
+
this.config.colors = enabled;
|
|
807
|
+
this.formatOptions.colors = enabled;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Update format
|
|
811
|
+
*/
|
|
812
|
+
setFormat(format) {
|
|
813
|
+
this.config.format = format;
|
|
814
|
+
this.formatOptions.format = format;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Update timestamp setting
|
|
818
|
+
*/
|
|
819
|
+
setTimestamp(enabled) {
|
|
820
|
+
this.config.timestamp = enabled;
|
|
821
|
+
this.formatOptions.timestamp = enabled;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Update timestamp format
|
|
825
|
+
*
|
|
826
|
+
* @param _format - 'time' | 'datetime' | 'full' (reserved for future use)
|
|
827
|
+
*/
|
|
828
|
+
setTimestampFormat(_format) {
|
|
829
|
+
// Timestamp format is handled by ecosystem-core formatTimestamp function
|
|
830
|
+
// This method is kept for API compatibility but doesn't modify formatOptions
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Format a timestamp using engine's timestamp formatter
|
|
834
|
+
* Useful for consistent timestamp formatting across the system
|
|
835
|
+
*
|
|
836
|
+
* @param date - Date to format (defaults to current time)
|
|
837
|
+
* @param format - Format type ('time', 'datetime', or 'full')
|
|
838
|
+
* @returns Formatted timestamp string
|
|
839
|
+
*/
|
|
840
|
+
formatTimestamp(date, format = 'time') {
|
|
841
|
+
return formatTimestamp(date || new Date(), format);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Check if a level will be logged (uses shouldLog from ecosystem-core)
|
|
845
|
+
*/
|
|
846
|
+
willLog(level) {
|
|
847
|
+
return shouldLog(level, this.config.level);
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Get current configuration
|
|
851
|
+
*/
|
|
852
|
+
getConfig() {
|
|
853
|
+
return { ...this.config };
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Check if debug logging is enabled
|
|
857
|
+
*/
|
|
858
|
+
isDebugEnabled() {
|
|
859
|
+
return this.willLog(LogLevel.DEBUG);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Check if info logging is enabled
|
|
863
|
+
*/
|
|
864
|
+
isInfoEnabled() {
|
|
865
|
+
return this.willLog(LogLevel.INFO);
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Check if warn logging is enabled
|
|
869
|
+
*/
|
|
870
|
+
isWarnEnabled() {
|
|
871
|
+
return this.willLog(LogLevel.WARN);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Check if error logging is enabled
|
|
875
|
+
*/
|
|
876
|
+
isErrorEnabled() {
|
|
877
|
+
return this.willLog(LogLevel.ERROR);
|
|
878
|
+
}
|
|
879
|
+
// ============================================================================
|
|
880
|
+
// JSON LOG BUFFER MANAGEMENT
|
|
881
|
+
// ============================================================================
|
|
882
|
+
/**
|
|
883
|
+
* Add event to JSON log buffer
|
|
884
|
+
*/
|
|
885
|
+
addToBuffer(event) {
|
|
886
|
+
// Add to buffer
|
|
887
|
+
this.logBuffer.push(event);
|
|
888
|
+
// Prevent buffer overflow
|
|
889
|
+
if (this.logBuffer.length > this.maxBufferSize) {
|
|
890
|
+
this.logBuffer.shift(); // Remove oldest log
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Get all logs as JSON array
|
|
895
|
+
* This is what CLI, API, dashboards, and explanation system will consume
|
|
896
|
+
*/
|
|
897
|
+
getJSONLogs() {
|
|
898
|
+
return [...this.logBuffer]; // Return copy to prevent external mutations
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Get logs filtered by type
|
|
902
|
+
*/
|
|
903
|
+
getLogsByType(type) {
|
|
904
|
+
return this.logBuffer.filter(log => log.type === type);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Get logs filtered by time range
|
|
908
|
+
*/
|
|
909
|
+
getLogsByTimeRange(startTime, endTime) {
|
|
910
|
+
return this.logBuffer.filter(log => log.timestamp >= startTime && log.timestamp <= endTime);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Get logs filtered by multiple criteria
|
|
914
|
+
*/
|
|
915
|
+
getLogsFiltered(filter) {
|
|
916
|
+
let filtered = this.logBuffer;
|
|
917
|
+
if (filter.types) {
|
|
918
|
+
filtered = filtered.filter(log => filter.types.includes(log.type));
|
|
919
|
+
}
|
|
920
|
+
if (filter.startTime) {
|
|
921
|
+
filtered = filtered.filter(log => log.timestamp >= filter.startTime);
|
|
922
|
+
}
|
|
923
|
+
if (filter.endTime) {
|
|
924
|
+
filtered = filtered.filter(log => log.timestamp <= filter.endTime);
|
|
925
|
+
}
|
|
926
|
+
if (filter.hasError !== undefined) {
|
|
927
|
+
filtered = filtered.filter(log => filter.hasError ? !!log.error : !log.error);
|
|
928
|
+
}
|
|
929
|
+
if (filter.searchText) {
|
|
930
|
+
const searchLower = filter.searchText.toLowerCase();
|
|
931
|
+
filtered = filtered.filter(log => log.message.toLowerCase().includes(searchLower));
|
|
932
|
+
}
|
|
933
|
+
return filtered;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Get logs by category: Parse events
|
|
937
|
+
*/
|
|
938
|
+
getParseLogEvents() {
|
|
939
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_VALIDATION);
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Get logs by category: Validation events
|
|
943
|
+
*/
|
|
944
|
+
getValidationLogEvents() {
|
|
945
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_VALIDATION ||
|
|
946
|
+
log.type === EngineLogType.VALIDATION_ERROR);
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Get logs by category: Execution events
|
|
950
|
+
*/
|
|
951
|
+
getExecutionLogEvents() {
|
|
952
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_STARTED ||
|
|
953
|
+
log.type === EngineLogType.WORKFLOW_COMPLETED ||
|
|
954
|
+
log.type === EngineLogType.WORKFLOW_FAILED ||
|
|
955
|
+
log.type === EngineLogType.STEP_STARTED ||
|
|
956
|
+
log.type === EngineLogType.STEP_COMPLETED ||
|
|
957
|
+
log.type === EngineLogType.STEP_FAILED ||
|
|
958
|
+
log.type === EngineLogType.STEP_RETRY ||
|
|
959
|
+
log.type === EngineLogType.STEP_TIMEOUT ||
|
|
960
|
+
log.type === EngineLogType.EXECUTION_TIME ||
|
|
961
|
+
log.type === EngineLogType.QUEUE_PROCESSING);
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Get logs by category: Error events
|
|
965
|
+
*/
|
|
966
|
+
getErrorLogEvents() {
|
|
967
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.ERROR_DETECTED ||
|
|
968
|
+
log.type === EngineLogType.ERROR_DEBUGGED ||
|
|
969
|
+
log.type === EngineLogType.VALIDATION_ERROR ||
|
|
970
|
+
log.type === EngineLogType.WORKFLOW_FAILED ||
|
|
971
|
+
log.type === EngineLogType.STEP_FAILED ||
|
|
972
|
+
log.type === EngineLogType.ADAPTER_FAILED ||
|
|
973
|
+
log.type === EngineLogType.ERROR);
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Get logs by category: Lifecycle events
|
|
977
|
+
*/
|
|
978
|
+
getLifecycleLogEvents() {
|
|
979
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.ENGINE_STARTED ||
|
|
980
|
+
log.type === EngineLogType.ENGINE_STOPPED ||
|
|
981
|
+
log.type === EngineLogType.ADAPTER_LOADED ||
|
|
982
|
+
log.type === EngineLogType.PLUGIN_INSTALLED ||
|
|
983
|
+
log.type === EngineLogType.PLUGIN_VERIFIED);
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Get logs by category: Performance events
|
|
987
|
+
*/
|
|
988
|
+
getPerformanceLogEvents() {
|
|
989
|
+
return this.logBuffer.filter(log => log.type === EngineLogType.PERFORMANCE_METRIC ||
|
|
990
|
+
log.type === EngineLogType.EXECUTION_TIME);
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Export logs as formatted JSON string
|
|
994
|
+
*/
|
|
995
|
+
exportLogsAsJSON(pretty = true) {
|
|
996
|
+
return JSON.stringify(this.logBuffer, null, pretty ? 2 : 0);
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Export logs grouped by type
|
|
1000
|
+
*/
|
|
1001
|
+
exportLogsGrouped() {
|
|
1002
|
+
const grouped = {};
|
|
1003
|
+
for (const log of this.logBuffer) {
|
|
1004
|
+
const type = log.type;
|
|
1005
|
+
if (!grouped[type]) {
|
|
1006
|
+
grouped[type] = [];
|
|
1007
|
+
}
|
|
1008
|
+
grouped[type].push(log);
|
|
1009
|
+
}
|
|
1010
|
+
return grouped;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Get log statistics
|
|
1014
|
+
*/
|
|
1015
|
+
getLogStats() {
|
|
1016
|
+
const stats = {
|
|
1017
|
+
total: this.logBuffer.length,
|
|
1018
|
+
byType: {},
|
|
1019
|
+
withErrors: 0,
|
|
1020
|
+
withMetrics: 0,
|
|
1021
|
+
timeRange: {
|
|
1022
|
+
first: this.logBuffer[0]?.timestamp,
|
|
1023
|
+
last: this.logBuffer[this.logBuffer.length - 1]?.timestamp,
|
|
1024
|
+
},
|
|
1025
|
+
};
|
|
1026
|
+
for (const log of this.logBuffer) {
|
|
1027
|
+
// Count by type
|
|
1028
|
+
stats.byType[log.type] = (stats.byType[log.type] || 0) + 1;
|
|
1029
|
+
// Count errors and metrics
|
|
1030
|
+
if (log.error)
|
|
1031
|
+
stats.withErrors++;
|
|
1032
|
+
if (log.metrics)
|
|
1033
|
+
stats.withMetrics++;
|
|
1034
|
+
}
|
|
1035
|
+
return stats;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Clear log buffer
|
|
1039
|
+
*/
|
|
1040
|
+
clearLogs() {
|
|
1041
|
+
this.logBuffer = [];
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Set maximum buffer size
|
|
1045
|
+
*/
|
|
1046
|
+
setMaxBufferSize(size) {
|
|
1047
|
+
this.maxBufferSize = size;
|
|
1048
|
+
// Trim buffer if needed
|
|
1049
|
+
while (this.logBuffer.length > this.maxBufferSize) {
|
|
1050
|
+
this.logBuffer.shift();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Get current buffer size
|
|
1055
|
+
*/
|
|
1056
|
+
getBufferSize() {
|
|
1057
|
+
return this.logBuffer.length;
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Export logs in a comprehensive format for consumers (CLI, API, dashboards)
|
|
1061
|
+
*/
|
|
1062
|
+
exportLogs() {
|
|
1063
|
+
const stats = this.getLogStats();
|
|
1064
|
+
const grouped = this.exportLogsGrouped();
|
|
1065
|
+
// Build execution summary from logs
|
|
1066
|
+
const execution = this.buildExecutionSummary();
|
|
1067
|
+
return {
|
|
1068
|
+
raw: this.getJSONLogs(),
|
|
1069
|
+
grouped,
|
|
1070
|
+
stats,
|
|
1071
|
+
execution,
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Build execution summary from collected logs
|
|
1076
|
+
* This powers dynamic explanation generation
|
|
1077
|
+
*/
|
|
1078
|
+
buildExecutionSummary() {
|
|
1079
|
+
const workflowLogs = this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_STARTED ||
|
|
1080
|
+
log.type === EngineLogType.WORKFLOW_COMPLETED ||
|
|
1081
|
+
log.type === EngineLogType.WORKFLOW_FAILED);
|
|
1082
|
+
const stepLogs = this.logBuffer.filter(log => log.type === EngineLogType.STEP_STARTED ||
|
|
1083
|
+
log.type === EngineLogType.STEP_COMPLETED ||
|
|
1084
|
+
log.type === EngineLogType.STEP_FAILED);
|
|
1085
|
+
const errorLogs = this.logBuffer.filter(log => log.error !== undefined ||
|
|
1086
|
+
log.type === EngineLogType.ERROR_DETECTED ||
|
|
1087
|
+
log.type === EngineLogType.VALIDATION_ERROR);
|
|
1088
|
+
const metricLogs = this.logBuffer.filter(log => log.type === EngineLogType.PERFORMANCE_METRIC ||
|
|
1089
|
+
log.type === EngineLogType.EXECUTION_TIME);
|
|
1090
|
+
// Extract workflow info
|
|
1091
|
+
let workflow;
|
|
1092
|
+
const workflowStarted = workflowLogs.find(log => log.type === EngineLogType.WORKFLOW_STARTED);
|
|
1093
|
+
const workflowEnded = workflowLogs.find(log => log.type === EngineLogType.WORKFLOW_COMPLETED ||
|
|
1094
|
+
log.type === EngineLogType.WORKFLOW_FAILED);
|
|
1095
|
+
if (workflowStarted && workflowEnded) {
|
|
1096
|
+
workflow = {
|
|
1097
|
+
name: workflowStarted.context?.workflowName || 'Unknown',
|
|
1098
|
+
status: workflowEnded.type === EngineLogType.WORKFLOW_COMPLETED ? 'completed' : 'failed',
|
|
1099
|
+
duration: workflowEnded.metrics?.duration,
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
// Extract step info
|
|
1103
|
+
const steps = [];
|
|
1104
|
+
const stepMap = new Map();
|
|
1105
|
+
for (const log of stepLogs) {
|
|
1106
|
+
const stepId = log.context?.stepId || '';
|
|
1107
|
+
const stepName = log.context?.stepName || '';
|
|
1108
|
+
if (!stepMap.has(stepId)) {
|
|
1109
|
+
stepMap.set(stepId, { id: stepId, name: stepName });
|
|
1110
|
+
}
|
|
1111
|
+
const step = stepMap.get(stepId);
|
|
1112
|
+
if (log.type === EngineLogType.STEP_COMPLETED) {
|
|
1113
|
+
step.status = 'completed';
|
|
1114
|
+
step.duration = log.metrics?.duration;
|
|
1115
|
+
}
|
|
1116
|
+
else if (log.type === EngineLogType.STEP_FAILED) {
|
|
1117
|
+
step.status = 'failed';
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
step.status = 'started';
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
steps.push(...stepMap.values());
|
|
1124
|
+
// Extract error info
|
|
1125
|
+
const errors = errorLogs.map(log => ({
|
|
1126
|
+
step: log.context?.stepId || log.context?.stepName,
|
|
1127
|
+
message: log.message,
|
|
1128
|
+
error: log.error,
|
|
1129
|
+
}));
|
|
1130
|
+
// Extract metrics
|
|
1131
|
+
const metrics = metricLogs.map(log => ({
|
|
1132
|
+
label: log.context?.label || 'Unknown',
|
|
1133
|
+
duration: log.metrics?.duration,
|
|
1134
|
+
memory: log.metrics?.memory,
|
|
1135
|
+
}));
|
|
1136
|
+
return {
|
|
1137
|
+
workflow,
|
|
1138
|
+
steps,
|
|
1139
|
+
errors,
|
|
1140
|
+
metrics,
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Create a logger instance from engine config
|
|
1146
|
+
*/
|
|
1147
|
+
export function createEngineLogger(logLevel, verbose = false) {
|
|
1148
|
+
// Silent mode - no logger
|
|
1149
|
+
if (logLevel === 'silent') {
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
// Map engine log level to ecosystem LogLevel
|
|
1153
|
+
const levelMap = {
|
|
1154
|
+
debug: LogLevel.DEBUG,
|
|
1155
|
+
info: LogLevel.INFO,
|
|
1156
|
+
warn: LogLevel.WARN,
|
|
1157
|
+
error: LogLevel.ERROR,
|
|
1158
|
+
fatal: LogLevel.FATAL,
|
|
1159
|
+
};
|
|
1160
|
+
const level = levelMap[logLevel] || LogLevel.INFO;
|
|
1161
|
+
return new EngineLogger({
|
|
1162
|
+
level,
|
|
1163
|
+
format: verbose ? 'pretty' : 'text',
|
|
1164
|
+
colors: true,
|
|
1165
|
+
timestamp: true, // Enable human-readable timestamps
|
|
1166
|
+
source: 'Orbyt',
|
|
1167
|
+
structuredEvents: true, // Always collect structured JSON logs
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
//# sourceMappingURL=EngineLogger.js.map
|