@live-change/framework 0.9.171 → 0.9.174

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.
@@ -2,6 +2,21 @@ import { prepareParameters, processReturn } from "./params.js"
2
2
  import SplitEmitQueue from "../utils/SplitEmitQueue.js"
3
3
  import SingleEmitQueue from "../utils/SingleEmitQueue.js"
4
4
 
5
+ import { context, propagation, trace } from '@opentelemetry/api'
6
+ import { SpanKind } from '@opentelemetry/api'
7
+ const tracer = trace.getTracer('live-change:triggerHandler')
8
+
9
+ import { expandObjectAttributes } from '../utils.js'
10
+
11
+ async function spanAttributes(trig, service) {
12
+ return {
13
+ ...expandObjectAttributes(trig, 'trigger'),
14
+ service: service.name
15
+ }
16
+ }
17
+
18
+ import { loggingHelpers } from '../utils.js'
19
+
5
20
  class TriggerHandler {
6
21
 
7
22
  constructor(definition, service) {
@@ -14,6 +29,10 @@ class TriggerHandler {
14
29
  Array.isArray(queuedBy) ? (c) => JSON.stringify(queuedBy.map(k=>c[k])) :
15
30
  (c) => JSON.stringify(c[queuedBy]) )
16
31
  }
32
+
33
+ this.loggingHelpers = loggingHelpers(service.name, service.app.config.clientConfig.version, {
34
+ triggerType: definition.name,
35
+ })
17
36
  }
18
37
 
19
38
  async doExecute(trig, emit) {
@@ -42,7 +61,8 @@ class TriggerHandler {
42
61
  cause: trig.id,
43
62
  client: trig.client,
44
63
  ...trigger
45
- }, data, returnArray)
64
+ }, data, returnArray),
65
+ ...this.loggingHelpers
46
66
  }, emit))
47
67
  //console.log("RESULT PROMISE", resultPromise, resultPromise.then)
48
68
  resultPromise = resultPromise.then(async result => {
@@ -50,75 +70,130 @@ class TriggerHandler {
50
70
  return processedResult
51
71
  })
52
72
  resultPromise.catch(error => {
53
- console.error(`Trigger ${this.definition.name} error `, error)
73
+ this.loggingHelpers.error(`Trigger ${this.definition.name} error `, error)
54
74
  })
55
75
  return resultPromise
56
76
  }
57
77
 
58
78
  async execute(trig, service) {
59
- console.log("EXECUTE", trig, this.queueKeyFunction)
79
+ //console.log("EXECUTE", trig, this.queueKeyFunction)
60
80
  const profileOp = await service.profileLog.begin({
61
81
  operation: 'queueTrigger', triggerType: this.definition.name,
62
82
  triggerId: trig.id, by: trig.by
63
83
  })
64
84
  if(this.queueKeyFunction) {
65
- console.log("QUEUED TRIGGER STARTED", trig)
66
- const routine = () => service.profileLog.profile({
67
- operation: 'runTrigger', triggerType: this.definition.name,
68
- commandId: trig.id, by: trig.by
69
- }, async () => {
70
- let result
71
- const reportFinished = this.definition.waitForEvents ? 'trigger_' + trig.id : undefined
72
- const flags = {triggerId: trig.id, reportFinished}
73
- const emit = service.app.splitEvents
74
- ? new SplitEmitQueue(service, flags)
75
- : new SingleEmitQueue(service, flags)
85
+ //console.log("QUEUED TRIGGER STARTED", trig)
86
+ return tracer.startActiveSpan('queueTrigger:'+service.name+'.'+this.definition.name, {
87
+ kind: SpanKind.INTERNAL,
88
+ attributes: spanAttributes(trig, service)
89
+ }, async (queueSpan) => {
90
+ const queueContext = context.active()
91
+
92
+ const routine = () => service.profileLog.profile({
93
+ operation: 'runTrigger', triggerType: this.definition.name,
94
+ commandId: trig.id, by: trig.by
95
+ }, async () => {
96
+ return tracer.startActiveSpan('handleTrigger:'+service.name+'.'+this.definition.name, {
97
+ kind: SpanKind.INTERNAL,
98
+ attributes: spanAttributes(trig, service)
99
+ }, queueContext, async (handleSpan) => {
100
+ let result
101
+ const reportFinished = this.definition.waitForEvents ? 'trigger_' + trig.id : undefined
102
+ const _trace = {}
103
+ propagation.inject(context.active(), _trace)
104
+ const flags = {triggerId: trig.id, reportFinished, _trace }
105
+ const emit = service.app.splitEvents
106
+ ? new SplitEmitQueue(service, flags)
107
+ : new SingleEmitQueue(service, flags)
108
+
109
+ await tracer.startActiveSpan('runTrigger', {
110
+ kind: SpanKind.SERVER,
111
+ attributes: spanAttributes(trig, service)
112
+ }, queueContext, async (runSpan) => {
113
+ try {
114
+ //console.log("TRIGGER RUNNING!", trig)
115
+
116
+ result = await service.app.assertTime('trigger ' + this.definition.name,
117
+ this.definition.timeout || 10000,
118
+ () => this.doExecute(trig, (...args) => emit.emit(...args)))
119
+ } catch (e) {
120
+ this.loggingHelpers.error(`Trigger ${this.definition.name} error `, e.stack)
121
+ runSpan.end()
122
+ handleSpan.end()
123
+ queueSpan.end()
124
+ throw e
125
+ }
126
+ runSpan.end()
127
+ return result
128
+ })
129
+ return await tracer.startActiveSpan('emitEvents', {
130
+ kind: SpanKind.INTERNAL,
131
+ attributes: spanAttributes(trig, service)
132
+ }, queueContext, async (emitEventsSpan) => {
133
+ const events = await emit.commit()
134
+ if (this.definition.waitForEvents)
135
+ await service.app.waitForEvents(reportFinished, events, this.definition.waitForEvents)
136
+ emitEventsSpan.end()
137
+ handleSpan.end()
138
+ queueSpan.end()
139
+ return result
140
+ })
141
+ })
142
+ })
76
143
  try {
77
- console.log("TRIGGER RUNNING!", trig)
78
- result = await service.app.assertTime('trigger ' + this.definition.name,
79
- this.definition.timeout || 10000,
80
- () => this.doExecute(trig, (...args) => emit.emit(...args)))
81
- console.log("TRIGGER DONE!", trig)
144
+ routine.key = this.queueKeyFunction(trig)
82
145
  } catch (e) {
83
- console.error(`TRIGGER ${this.definition.name} ERROR`, e.stack)
84
- throw e
146
+ this.loggingHelpers.error("Queue key function error ", e)
85
147
  }
86
- const events = await emit.commit()
87
- if (this.definition.waitForEvents)
88
- await service.app.waitForEvents(reportFinished, events, this.definition.waitForEvents)
89
- return result
148
+ this.loggingHelpers.log("Trigger queue key", routine.key)
149
+ const promise = service.keyBasedExecutionQueues.queue(routine)
150
+ await service.profileLog.endPromise(profileOp, promise)
151
+ return promise
90
152
  })
91
- try {
92
- routine.key = this.queueKeyFunction(trig)
93
- } catch (e) {
94
- console.error("QUEUE KEY FUNCTION ERROR", e)
95
- }
96
- console.log("TRIGGER QUEUE KEY", routine.key)
97
- const promise = service.keyBasedExecutionQueues.queue(routine)
98
- await service.profileLog.endPromise(profileOp, promise)
99
- return promise
100
153
  } else {
101
- console.log("NOT QUEUED TRIGGER STARTED", trig)
102
- const reportFinished = this.definition.waitForEvents ? 'trigger_'+trig.id : undefined
103
- const flags = { triggerId: trig.id, reportFinished }
104
- const emit = service.app.splitEvents
105
- ? new SplitEmitQueue(service, flags)
106
- : new SingleEmitQueue(service, flags)
107
- let result
108
- try {
109
- result = await service.app.assertTime('trigger '+this.definition.name,
110
- this.definition.timeout || 10000,
111
- () => this.doExecute(trig, (...args) => emit.emit(...args)))
112
- console.log("TRIGGER DONE!", trig)
113
- } catch (e) {
114
- console.error(`TRIGGER ${this.definition.name} ERROR`, e.stack)
115
- throw e
116
- }
117
- const events = await emit.commit()
118
- if(this.definition.waitForEvents)
119
- await service.app.waitForEvents(reportFinished, events, this.definition.waitForEvents)
120
- await service.profileLog.end(profileOp)
121
- return result
154
+ return tracer.startActiveSpan('handleTrigger:'+service.name+'.'+this.definition.name, {
155
+ kind: SpanKind.INTERNAL,
156
+ attributes: spanAttributes(trig, service)
157
+ }, async (handleSpan) => {
158
+ this.loggingHelpers.log("Not queued trigger started", trig)
159
+ const reportFinished = this.definition.waitForEvents ? 'trigger_'+trig.id : undefined
160
+ const _trace = {}
161
+ propagation.inject(context.active(), _trace)
162
+ const flags = { triggerId: trig.id, reportFinished, _trace }
163
+ const emit = service.app.splitEvents
164
+ ? new SplitEmitQueue(service, flags)
165
+ : new SingleEmitQueue(service, flags)
166
+ let result
167
+ await tracer.startActiveSpan('runTrigger:'+service.name+'.'+this.definition.name, {
168
+ kind: SpanKind.SERVER,
169
+ attributes: spanAttributes(trig, service)
170
+ }, async (runSpan) => {
171
+ try {
172
+ result = await service.app.assertTime('trigger '+this.definition.name,
173
+ this.definition.timeout || 10000,
174
+ () => this.doExecute(trig, (...args) => emit.emit(...args)))
175
+ runSpan.end()
176
+ this.loggingHelpers.log("Trigger done", trig)
177
+ } catch (e) {
178
+ this.loggingHelpers.error(`Trigger ${this.definition.name} error `, e.stack)
179
+ runSpan.end()
180
+ handleSpan.end()
181
+ throw e
182
+ }
183
+ })
184
+ return tracer.startActiveSpan('emitEvents', {
185
+ kind: SpanKind.INTERNAL,
186
+ attributes: spanAttributes(trig, service)
187
+ }, async (emitEventsSpan) => {
188
+ const events = await emit.commit()
189
+ if(this.definition.waitForEvents)
190
+ await service.app.waitForEvents(reportFinished, events, this.definition.waitForEvents)
191
+ emitEventsSpan.end()
192
+ handleSpan.end()
193
+ await service.profileLog.end(profileOp)
194
+ return result
195
+ })
196
+ })
122
197
  }
123
198
  }
124
199
 
package/lib/utils.js CHANGED
@@ -365,4 +365,63 @@ export function parseDuration(duration) {
365
365
  result += value * { s: 1000, m: 60000, h: 3600000, d: 86400000 }[unit]
366
366
  }
367
367
  return result
368
+ }
369
+
370
+ import { logs, SeverityNumber } from '@opentelemetry/api-logs'
371
+ import { context } from '@opentelemetry/api'
372
+
373
+ export function loggingHelper(logger, severityNumber, severityText, attributes) {
374
+ return (message, ...args) => {
375
+ logger.emit({
376
+ severityNumber, severityText,
377
+ body: [message, ...args].map(a => {
378
+ try {
379
+ return JSON.stringify(a)
380
+ } catch (e) {
381
+ return `${a}`
382
+ }
383
+ }).join(' '),
384
+ attributes: {
385
+ ...attributes,
386
+ 'log.type': 'LogRecord',
387
+ message,
388
+ logArgs: args.map(a => {
389
+ try {
390
+ return JSON.stringify(a)
391
+ } catch (e) {
392
+ return `${a}`
393
+ }
394
+ }),
395
+ },
396
+ context: context.active()
397
+ })
398
+ }
399
+ }
400
+
401
+ export function loggingHelpers(name, version, attributes, options) {
402
+ const logger = logs.getLogger(name, version, options)
403
+ return {
404
+ log: loggingHelper(logger, SeverityNumber.INFO, 'INFO', attributes),
405
+ warn: loggingHelper(logger, SeverityNumber.WARN, 'WARN', attributes),
406
+ error: loggingHelper(logger, SeverityNumber.ERROR, 'ERROR', attributes),
407
+ debug: loggingHelper(logger, SeverityNumber.DEBUG, 'DEBUG', attributes),
408
+ trace: loggingHelper(logger, SeverityNumber.TRACE, 'TRACE', attributes),
409
+ fatal: loggingHelper(logger, SeverityNumber.FATAL, 'FATAL', attributes),
410
+ }
411
+ }
412
+
413
+ export function expandObjectAttributes(object, prefix = '', acc = {}) {
414
+ if(typeof object !== 'object') {
415
+ acc[prefix] = object
416
+ return
417
+ }
418
+ if(object === null || object === undefined) {
419
+ acc[prefix] = object
420
+ return
421
+ }
422
+ //if(Array.isArray(object)) return object.map(item => expandObjectAttributes(item, prefix))
423
+ for(const [key, value] of Object.entries(object)) {
424
+ expandObjectAttributes(value, prefix + '_' + key, acc)
425
+ }
426
+ return acc
368
427
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/framework",
3
- "version": "0.9.171",
3
+ "version": "0.9.174",
4
4
  "description": "Live Change Framework - ultimate solution for real time mobile/web apps",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "homepage": "https://github.com/live-change/live-change-stack",
24
24
  "devDependencies": {
25
- "@live-change/dao": "^0.9.171",
26
- "@live-change/uid": "^0.9.171",
25
+ "@live-change/dao": "^0.9.174",
26
+ "@live-change/uid": "^0.9.174",
27
27
  "typedoc": "0.28.3",
28
28
  "typedoc-plugin-markdown": "^4.6.3",
29
29
  "typedoc-plugin-rename-defaults": "^0.7.3"
30
30
  },
31
- "gitHead": "2a684f9d6b097ef5b8e1e08edb4995949ee33330"
31
+ "gitHead": "6ebdadad702526df240bd3aa7ac3d97324a0308a"
32
32
  }
package/tsconfig.json CHANGED
@@ -20,11 +20,12 @@
20
20
  "esModuleInterop": true, // Enable interop for ES modules
21
21
  "resolveJsonModule": true, // Allow importing JSON files
22
22
  "skipLibCheck": true,
23
- "noImplicitAny": false
23
+ "noImplicitAny": false,
24
+ "types": []
24
25
  },
25
26
  "files": ["index.ts"],
26
27
  "include": [
27
28
  "lib/**/*.ts", "lib/**/*.js", "index.ts"],
28
- "exclude": ["node_modules/@types", "node_modules/**/*.d.ts", "**/*.test.js", "**/CMakeFiles/**"]
29
+ "exclude": ["node_modules/@types", "node_modules/**/*.d.ts", "**/*.test.js", "**/CMakeFiles/**", "**/node_modules/@hapi/**"]
29
30
  }
30
31