autotel-effect 3.0.0 → 4.0.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 +30 -1
- package/dist/index.cjs +81 -2
- package/dist/index.d.cts +38 -4
- package/dist/index.d.ts +38 -4
- package/dist/index.js +78 -3
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -75,7 +75,36 @@ appLayer.pipe(Layer.provideMerge(layer({ serviceName: 'my-api' })));
|
|
|
75
75
|
|
|
76
76
|
HTTP spans from autotel's `node:http` instrumentation become parents of domain spans from `Effect.withSpan`.
|
|
77
77
|
|
|
78
|
-
### 3.
|
|
78
|
+
### 3. Logs come with it
|
|
79
|
+
|
|
80
|
+
One `layer()` call bridges both signals. `Effect.log*` becomes an OpenTelemetry
|
|
81
|
+
**log record** (so it reaches any OTLP log backend, including autotel-devtools)
|
|
82
|
+
plus a trace-correlated structured line on stdout — no second layer to remember:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const AutotelEffect = layer({ serviceName: 'my-api' }); // spans + logs
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Pass `logs: false` for spans only, or an options object to configure the
|
|
89
|
+
logger. Log annotations become log metadata, and failure causes are logged as
|
|
90
|
+
`err`:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
Effect.log('charged').pipe(Effect.annotateLogs({ 'order.id': 'o-1' }));
|
|
94
|
+
// {"level":"info","msg":"charged","order.id":"o-1","traceId":"...","spanId":"..."}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Errors keep their stack: a `Cause` passed to `Effect.logError` (or an `Error`
|
|
98
|
+
in the message parts) is logged as `err` rather than stringified into `msg`.
|
|
99
|
+
|
|
100
|
+
Options: `mergeWithExisting: true` keeps Effect's console logger alongside this
|
|
101
|
+
one; `level` sets the stdout minimum level (default `'info'` — leave it there
|
|
102
|
+
and `Effect.logDebug` never reaches stdout even when Effect's own minimum level
|
|
103
|
+
allows it); `pretty: true` swaps JSON for human-readable stdout; `console: false`
|
|
104
|
+
drops the stdout line and emits only the log record — use it when
|
|
105
|
+
`captureConsole()` is on, or every Effect log is reported twice.
|
|
106
|
+
|
|
107
|
+
### 4. Unit tests: provide nothing
|
|
79
108
|
|
|
80
109
|
Effect's default `Tracer` is already an in-memory native tracer, so handler tests
|
|
81
110
|
need no layer at all — `Effect.withSpan` runs and exports nowhere:
|
package/dist/index.cjs
CHANGED
|
@@ -25,20 +25,99 @@ let _effect_opentelemetry_OtelTracer = require("@effect/opentelemetry/OtelTracer
|
|
|
25
25
|
_effect_opentelemetry_OtelTracer = __toESM(_effect_opentelemetry_OtelTracer, 1);
|
|
26
26
|
let _effect_opentelemetry_Resource = require("@effect/opentelemetry/Resource");
|
|
27
27
|
_effect_opentelemetry_Resource = __toESM(_effect_opentelemetry_Resource, 1);
|
|
28
|
+
let _opentelemetry_api_logs = require("@opentelemetry/api-logs");
|
|
29
|
+
let autotel_logger = require("autotel/logger");
|
|
30
|
+
let effect_Cause = require("effect/Cause");
|
|
31
|
+
effect_Cause = __toESM(effect_Cause, 1);
|
|
28
32
|
let effect_Layer = require("effect/Layer");
|
|
29
33
|
effect_Layer = __toESM(effect_Layer, 1);
|
|
34
|
+
let effect_Logger = require("effect/Logger");
|
|
35
|
+
effect_Logger = __toESM(effect_Logger, 1);
|
|
36
|
+
let effect_References = require("effect/References");
|
|
37
|
+
effect_References = __toESM(effect_References, 1);
|
|
30
38
|
//#region src/index.ts
|
|
31
39
|
/**
|
|
32
|
-
* Routes `Effect.withSpan` through autotel's global
|
|
40
|
+
* Routes `Effect.withSpan` and `Effect.log*` through autotel's global
|
|
41
|
+
* OpenTelemetry provider.
|
|
33
42
|
*
|
|
34
43
|
* Call `autotel.init()` before this layer is built — typically by loading an
|
|
35
44
|
* instrumentation module with `node --import` or `tsx --import`.
|
|
36
45
|
*/
|
|
37
46
|
function layer(options) {
|
|
38
|
-
|
|
47
|
+
const tracer = _effect_opentelemetry_OtelTracer.layerGlobal.pipe(effect_Layer.provide(_effect_opentelemetry_Resource.layer({
|
|
39
48
|
serviceName: options.serviceName,
|
|
40
49
|
...options.serviceVersion ? { serviceVersion: options.serviceVersion } : {}
|
|
41
50
|
})));
|
|
51
|
+
const logs = options.logs ?? true;
|
|
52
|
+
return effect_Layer.mergeAll(tracer, logs === false ? effect_Layer.empty : loggerLayer({
|
|
53
|
+
serviceName: options.serviceName,
|
|
54
|
+
...options.serviceVersion ? { serviceVersion: options.serviceVersion } : {},
|
|
55
|
+
...logs === true ? {} : logs
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Routes Effect's `Effect.log*` through autotel instead of Effect's console
|
|
60
|
+
* logger, emitting each log as an OpenTelemetry log record (so it reaches any
|
|
61
|
+
* OTLP log backend, autotel-devtools included) and, unless disabled, a
|
|
62
|
+
* structured line on stdout via autotel's built-in logger.
|
|
63
|
+
*
|
|
64
|
+
* `layer()` already includes this. Reach for it on its own only when something
|
|
65
|
+
* else owns the tracer and you want autotel to own the logs.
|
|
66
|
+
*/
|
|
67
|
+
function loggerLayer(options) {
|
|
68
|
+
const log = (0, autotel_logger.createBuiltinLogger)(options.serviceName, {
|
|
69
|
+
...options.level ? { level: options.level } : {},
|
|
70
|
+
...options.pretty ? { pretty: options.pretty } : {}
|
|
71
|
+
});
|
|
72
|
+
const otelLogger = () => _opentelemetry_api_logs.logs.getLogger(options.serviceName, options.serviceVersion);
|
|
73
|
+
return effect_Logger.layer([effect_Logger.make(({ cause, fiber, logLevel, message }) => {
|
|
74
|
+
const method = LEVEL_TO_METHOD[logLevel];
|
|
75
|
+
if (!method) return;
|
|
76
|
+
const parts = Array.isArray(message) ? message : [message];
|
|
77
|
+
const metadata = { ...fiber.getRef(effect_References.CurrentLogAnnotations) };
|
|
78
|
+
const errors = parts.filter((part) => part instanceof Error);
|
|
79
|
+
if (cause.reasons.length > 0) metadata.err = effect_Cause.pretty(cause);
|
|
80
|
+
else if (errors.length > 0) metadata.err = errors.map((error) => error.stack ?? String(error));
|
|
81
|
+
const body = parts.map(formatPart).join(" ");
|
|
82
|
+
if (options.console ?? true) log[method](metadata, body);
|
|
83
|
+
otelLogger().emit({
|
|
84
|
+
body,
|
|
85
|
+
severityNumber: LEVEL_TO_SEVERITY[logLevel],
|
|
86
|
+
severityText: logLevel,
|
|
87
|
+
attributes: {
|
|
88
|
+
...metadata,
|
|
89
|
+
...Array.isArray(metadata.err) ? { err: metadata.err.join("\n") } : {}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
})], { mergeWithExisting: options.mergeWithExisting ?? false });
|
|
93
|
+
}
|
|
94
|
+
const LEVEL_TO_METHOD = {
|
|
95
|
+
Trace: "debug",
|
|
96
|
+
Debug: "debug",
|
|
97
|
+
Info: "info",
|
|
98
|
+
Warn: "warn",
|
|
99
|
+
Error: "error",
|
|
100
|
+
Fatal: "error"
|
|
101
|
+
};
|
|
102
|
+
const LEVEL_TO_SEVERITY = {
|
|
103
|
+
All: _opentelemetry_api_logs.SeverityNumber.UNSPECIFIED,
|
|
104
|
+
Trace: _opentelemetry_api_logs.SeverityNumber.TRACE,
|
|
105
|
+
Debug: _opentelemetry_api_logs.SeverityNumber.DEBUG,
|
|
106
|
+
Info: _opentelemetry_api_logs.SeverityNumber.INFO,
|
|
107
|
+
Warn: _opentelemetry_api_logs.SeverityNumber.WARN,
|
|
108
|
+
Error: _opentelemetry_api_logs.SeverityNumber.ERROR,
|
|
109
|
+
Fatal: _opentelemetry_api_logs.SeverityNumber.FATAL,
|
|
110
|
+
None: _opentelemetry_api_logs.SeverityNumber.UNSPECIFIED
|
|
111
|
+
};
|
|
112
|
+
function formatPart(part) {
|
|
113
|
+
if (typeof part === "string") return part;
|
|
114
|
+
if (part instanceof Error) return String(part);
|
|
115
|
+
try {
|
|
116
|
+
return JSON.stringify(part) ?? String(part);
|
|
117
|
+
} catch {
|
|
118
|
+
return String(part);
|
|
119
|
+
}
|
|
42
120
|
}
|
|
43
121
|
//#endregion
|
|
44
122
|
exports.layer = layer;
|
|
123
|
+
exports.loggerLayer = loggerLayer;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,16 +1,50 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BuiltinLoggerOptions } from "autotel/logger";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
3
|
//#region src/index.d.ts
|
|
4
|
+
interface AutotelEffectLoggerOptions {
|
|
5
|
+
/** Keep Effect's default console logger alongside this one. Default: false. */
|
|
6
|
+
readonly mergeWithExisting?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Minimum level autotel's logger emits to stdout. Default: `'info'` — leave
|
|
9
|
+
* it there and `Effect.logDebug` never reaches stdout even when Effect's own
|
|
10
|
+
* minimum log level allows it.
|
|
11
|
+
*/
|
|
12
|
+
readonly level?: BuiltinLoggerOptions['level'];
|
|
13
|
+
/** Pretty-print the stdout line instead of JSON. Default: false. */
|
|
14
|
+
readonly pretty?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Also write each log to stdout via autotel's built-in logger.
|
|
17
|
+
* Default: true. Set to false when `captureConsole()` is on, otherwise
|
|
18
|
+
* every Effect log is reported twice.
|
|
19
|
+
*/
|
|
20
|
+
readonly console?: boolean;
|
|
21
|
+
}
|
|
4
22
|
interface AutotelEffectLayerOptions {
|
|
5
23
|
readonly serviceName: string;
|
|
6
24
|
readonly serviceVersion?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Bridge `Effect.log*` as well as spans. Default: `true`. Pass `false` for
|
|
27
|
+
* spans only, or an options object to configure the logger.
|
|
28
|
+
*/
|
|
29
|
+
readonly logs?: boolean | AutotelEffectLoggerOptions;
|
|
7
30
|
}
|
|
8
31
|
/**
|
|
9
|
-
* Routes `Effect.withSpan` through autotel's global
|
|
32
|
+
* Routes `Effect.withSpan` and `Effect.log*` through autotel's global
|
|
33
|
+
* OpenTelemetry provider.
|
|
10
34
|
*
|
|
11
35
|
* Call `autotel.init()` before this layer is built — typically by loading an
|
|
12
36
|
* instrumentation module with `node --import` or `tsx --import`.
|
|
13
37
|
*/
|
|
14
|
-
declare function layer(options: AutotelEffectLayerOptions): Layer.Layer<
|
|
38
|
+
declare function layer(options: AutotelEffectLayerOptions): Layer.Layer<never>;
|
|
39
|
+
/**
|
|
40
|
+
* Routes Effect's `Effect.log*` through autotel instead of Effect's console
|
|
41
|
+
* logger, emitting each log as an OpenTelemetry log record (so it reaches any
|
|
42
|
+
* OTLP log backend, autotel-devtools included) and, unless disabled, a
|
|
43
|
+
* structured line on stdout via autotel's built-in logger.
|
|
44
|
+
*
|
|
45
|
+
* `layer()` already includes this. Reach for it on its own only when something
|
|
46
|
+
* else owns the tracer and you want autotel to own the logs.
|
|
47
|
+
*/
|
|
48
|
+
declare function loggerLayer(options: Omit<AutotelEffectLayerOptions, 'logs'> & AutotelEffectLoggerOptions): Layer.Layer<never, never, never>;
|
|
15
49
|
//#endregion
|
|
16
|
-
export { AutotelEffectLayerOptions, layer };
|
|
50
|
+
export { AutotelEffectLayerOptions, AutotelEffectLoggerOptions, layer, loggerLayer };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,50 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BuiltinLoggerOptions } from "autotel/logger";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
3
|
//#region src/index.d.ts
|
|
4
|
+
interface AutotelEffectLoggerOptions {
|
|
5
|
+
/** Keep Effect's default console logger alongside this one. Default: false. */
|
|
6
|
+
readonly mergeWithExisting?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Minimum level autotel's logger emits to stdout. Default: `'info'` — leave
|
|
9
|
+
* it there and `Effect.logDebug` never reaches stdout even when Effect's own
|
|
10
|
+
* minimum log level allows it.
|
|
11
|
+
*/
|
|
12
|
+
readonly level?: BuiltinLoggerOptions['level'];
|
|
13
|
+
/** Pretty-print the stdout line instead of JSON. Default: false. */
|
|
14
|
+
readonly pretty?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Also write each log to stdout via autotel's built-in logger.
|
|
17
|
+
* Default: true. Set to false when `captureConsole()` is on, otherwise
|
|
18
|
+
* every Effect log is reported twice.
|
|
19
|
+
*/
|
|
20
|
+
readonly console?: boolean;
|
|
21
|
+
}
|
|
4
22
|
interface AutotelEffectLayerOptions {
|
|
5
23
|
readonly serviceName: string;
|
|
6
24
|
readonly serviceVersion?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Bridge `Effect.log*` as well as spans. Default: `true`. Pass `false` for
|
|
27
|
+
* spans only, or an options object to configure the logger.
|
|
28
|
+
*/
|
|
29
|
+
readonly logs?: boolean | AutotelEffectLoggerOptions;
|
|
7
30
|
}
|
|
8
31
|
/**
|
|
9
|
-
* Routes `Effect.withSpan` through autotel's global
|
|
32
|
+
* Routes `Effect.withSpan` and `Effect.log*` through autotel's global
|
|
33
|
+
* OpenTelemetry provider.
|
|
10
34
|
*
|
|
11
35
|
* Call `autotel.init()` before this layer is built — typically by loading an
|
|
12
36
|
* instrumentation module with `node --import` or `tsx --import`.
|
|
13
37
|
*/
|
|
14
|
-
declare function layer(options: AutotelEffectLayerOptions): Layer.Layer<
|
|
38
|
+
declare function layer(options: AutotelEffectLayerOptions): Layer.Layer<never>;
|
|
39
|
+
/**
|
|
40
|
+
* Routes Effect's `Effect.log*` through autotel instead of Effect's console
|
|
41
|
+
* logger, emitting each log as an OpenTelemetry log record (so it reaches any
|
|
42
|
+
* OTLP log backend, autotel-devtools included) and, unless disabled, a
|
|
43
|
+
* structured line on stdout via autotel's built-in logger.
|
|
44
|
+
*
|
|
45
|
+
* `layer()` already includes this. Reach for it on its own only when something
|
|
46
|
+
* else owns the tracer and you want autotel to own the logs.
|
|
47
|
+
*/
|
|
48
|
+
declare function loggerLayer(options: Omit<AutotelEffectLayerOptions, 'logs'> & AutotelEffectLoggerOptions): Layer.Layer<never, never, never>;
|
|
15
49
|
//#endregion
|
|
16
|
-
export { AutotelEffectLayerOptions, layer };
|
|
50
|
+
export { AutotelEffectLayerOptions, AutotelEffectLoggerOptions, layer, loggerLayer };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,93 @@
|
|
|
1
1
|
import * as OtelTracer from "@effect/opentelemetry/OtelTracer";
|
|
2
2
|
import * as Resource from "@effect/opentelemetry/Resource";
|
|
3
|
+
import { SeverityNumber, logs } from "@opentelemetry/api-logs";
|
|
4
|
+
import { createBuiltinLogger } from "autotel/logger";
|
|
5
|
+
import * as Cause from "effect/Cause";
|
|
3
6
|
import * as Layer from "effect/Layer";
|
|
7
|
+
import * as Logger from "effect/Logger";
|
|
8
|
+
import * as References from "effect/References";
|
|
4
9
|
//#region src/index.ts
|
|
5
10
|
/**
|
|
6
|
-
* Routes `Effect.withSpan` through autotel's global
|
|
11
|
+
* Routes `Effect.withSpan` and `Effect.log*` through autotel's global
|
|
12
|
+
* OpenTelemetry provider.
|
|
7
13
|
*
|
|
8
14
|
* Call `autotel.init()` before this layer is built — typically by loading an
|
|
9
15
|
* instrumentation module with `node --import` or `tsx --import`.
|
|
10
16
|
*/
|
|
11
17
|
function layer(options) {
|
|
12
|
-
|
|
18
|
+
const tracer = OtelTracer.layerGlobal.pipe(Layer.provide(Resource.layer({
|
|
13
19
|
serviceName: options.serviceName,
|
|
14
20
|
...options.serviceVersion ? { serviceVersion: options.serviceVersion } : {}
|
|
15
21
|
})));
|
|
22
|
+
const logs = options.logs ?? true;
|
|
23
|
+
return Layer.mergeAll(tracer, logs === false ? Layer.empty : loggerLayer({
|
|
24
|
+
serviceName: options.serviceName,
|
|
25
|
+
...options.serviceVersion ? { serviceVersion: options.serviceVersion } : {},
|
|
26
|
+
...logs === true ? {} : logs
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Routes Effect's `Effect.log*` through autotel instead of Effect's console
|
|
31
|
+
* logger, emitting each log as an OpenTelemetry log record (so it reaches any
|
|
32
|
+
* OTLP log backend, autotel-devtools included) and, unless disabled, a
|
|
33
|
+
* structured line on stdout via autotel's built-in logger.
|
|
34
|
+
*
|
|
35
|
+
* `layer()` already includes this. Reach for it on its own only when something
|
|
36
|
+
* else owns the tracer and you want autotel to own the logs.
|
|
37
|
+
*/
|
|
38
|
+
function loggerLayer(options) {
|
|
39
|
+
const log = createBuiltinLogger(options.serviceName, {
|
|
40
|
+
...options.level ? { level: options.level } : {},
|
|
41
|
+
...options.pretty ? { pretty: options.pretty } : {}
|
|
42
|
+
});
|
|
43
|
+
const otelLogger = () => logs.getLogger(options.serviceName, options.serviceVersion);
|
|
44
|
+
return Logger.layer([Logger.make(({ cause, fiber, logLevel, message }) => {
|
|
45
|
+
const method = LEVEL_TO_METHOD[logLevel];
|
|
46
|
+
if (!method) return;
|
|
47
|
+
const parts = Array.isArray(message) ? message : [message];
|
|
48
|
+
const metadata = { ...fiber.getRef(References.CurrentLogAnnotations) };
|
|
49
|
+
const errors = parts.filter((part) => part instanceof Error);
|
|
50
|
+
if (cause.reasons.length > 0) metadata.err = Cause.pretty(cause);
|
|
51
|
+
else if (errors.length > 0) metadata.err = errors.map((error) => error.stack ?? String(error));
|
|
52
|
+
const body = parts.map(formatPart).join(" ");
|
|
53
|
+
if (options.console ?? true) log[method](metadata, body);
|
|
54
|
+
otelLogger().emit({
|
|
55
|
+
body,
|
|
56
|
+
severityNumber: LEVEL_TO_SEVERITY[logLevel],
|
|
57
|
+
severityText: logLevel,
|
|
58
|
+
attributes: {
|
|
59
|
+
...metadata,
|
|
60
|
+
...Array.isArray(metadata.err) ? { err: metadata.err.join("\n") } : {}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
})], { mergeWithExisting: options.mergeWithExisting ?? false });
|
|
64
|
+
}
|
|
65
|
+
const LEVEL_TO_METHOD = {
|
|
66
|
+
Trace: "debug",
|
|
67
|
+
Debug: "debug",
|
|
68
|
+
Info: "info",
|
|
69
|
+
Warn: "warn",
|
|
70
|
+
Error: "error",
|
|
71
|
+
Fatal: "error"
|
|
72
|
+
};
|
|
73
|
+
const LEVEL_TO_SEVERITY = {
|
|
74
|
+
All: SeverityNumber.UNSPECIFIED,
|
|
75
|
+
Trace: SeverityNumber.TRACE,
|
|
76
|
+
Debug: SeverityNumber.DEBUG,
|
|
77
|
+
Info: SeverityNumber.INFO,
|
|
78
|
+
Warn: SeverityNumber.WARN,
|
|
79
|
+
Error: SeverityNumber.ERROR,
|
|
80
|
+
Fatal: SeverityNumber.FATAL,
|
|
81
|
+
None: SeverityNumber.UNSPECIFIED
|
|
82
|
+
};
|
|
83
|
+
function formatPart(part) {
|
|
84
|
+
if (typeof part === "string") return part;
|
|
85
|
+
if (part instanceof Error) return String(part);
|
|
86
|
+
try {
|
|
87
|
+
return JSON.stringify(part) ?? String(part);
|
|
88
|
+
} catch {
|
|
89
|
+
return String(part);
|
|
90
|
+
}
|
|
16
91
|
}
|
|
17
92
|
//#endregion
|
|
18
|
-
export { layer };
|
|
93
|
+
export { layer, loggerLayer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-effect",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Bridge autotel and Effect v4: Effect.withSpan spans export through autotel's global TracerProvider",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -50,14 +50,19 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@effect/opentelemetry": "4.0.0-rc.112",
|
|
53
|
+
"@opentelemetry/api-logs": "^0.222.0",
|
|
54
|
+
"@opentelemetry/sdk-logs": "^0.222.0",
|
|
53
55
|
"@types/node": "^26.1.2",
|
|
54
|
-
"autotel": "7.6.
|
|
56
|
+
"autotel": "7.6.1",
|
|
55
57
|
"effect": "4.0.0-rc.112",
|
|
56
58
|
"rimraf": "^6.1.3",
|
|
57
59
|
"tsdown": "^0.22.14",
|
|
58
60
|
"typescript": "^6.0.3",
|
|
59
61
|
"vitest": "^4.1.10"
|
|
60
62
|
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@opentelemetry/api-logs": "^0.222.0"
|
|
65
|
+
},
|
|
61
66
|
"scripts": {
|
|
62
67
|
"build": "tsdown",
|
|
63
68
|
"dev": "tsdown --watch",
|