autotel-effect 5.0.0 → 5.0.2

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 CHANGED
@@ -138,6 +138,8 @@ Effect.annotateLogs({ order: { id: 7 }, at: new Date(0) });
138
138
 
139
139
  Errors keep their stack: a `Cause` passed to `Effect.logError` (or an `Error`
140
140
  in the message parts) is logged as `err` rather than stringified into `msg`.
141
+ `Effect.withLogSpan('db')` adds `logSpan.db` in milliseconds. The record's
142
+ timestamp comes from the fiber's clock, so a test clock sets the time you see.
141
143
 
142
144
  Options: `mergeWithExisting: true` keeps Effect's console logger alongside this
143
145
  one; `level` sets the stdout minimum level (default `'info'` — leave it there
@@ -170,6 +172,19 @@ HTTP GET /api/todos (autotel node:http)
170
172
 
171
173
  Without `withAutotel`, `todo.list` is the root of a second, unrelated trace.
172
174
 
175
+ ### Failures: put the detail in `message`
176
+
177
+ When a span fails, `@effect/opentelemetry` records `exception.message` and the
178
+ span status message from `error.message`. `Data.TaggedError` sets that from a
179
+ `message` prop. The `Error` constructor writes `message` as an own property,
180
+ which shadows a getter on the class, so `new NotFound({ reason: "..." })`
181
+ reaches your backend with an empty message ("Unknown error" in
182
+ autotel-devtools). Name the prop `message`:
183
+
184
+ ```ts
185
+ class NotFound extends Data.TaggedError('NotFound')<{ message: string }> {}
186
+ ```
187
+
173
188
  ## Example
174
189
 
175
190
  See [`apps/example-effect`](../../apps/example-effect) in the autotel monorepo.
package/dist/index.cjs CHANGED
@@ -91,11 +91,12 @@ function loggerLayer(options) {
91
91
  ...options.pretty ? { pretty: options.pretty } : {}
92
92
  });
93
93
  const otelLogger = () => _opentelemetry_api_logs.logs.getLogger(options.serviceName, options.serviceVersion);
94
- return effect_Logger.layer([effect_Logger.make(({ cause, fiber, logLevel, message }) => {
94
+ return effect_Logger.layer([effect_Logger.make(({ cause, date, fiber, logLevel, message }) => {
95
95
  const method = LEVEL_TO_METHOD[logLevel];
96
96
  if (!method) return;
97
97
  const parts = Array.isArray(message) ? message : [message];
98
98
  const metadata = { ...fiber.getRef(effect_References.CurrentLogAnnotations) };
99
+ for (const [label, start] of fiber.getRef(effect_References.CurrentLogSpans)) metadata[`logSpan.${label}`] = date.getTime() - start;
99
100
  const errors = parts.filter((part) => part instanceof Error);
100
101
  if (cause.reasons.length > 0) metadata.err = effect_Cause.pretty(cause);
101
102
  else if (errors.length > 0) metadata.err = errors.map((error) => error.stack ?? String(error));
@@ -103,6 +104,7 @@ function loggerLayer(options) {
103
104
  if (options.console ?? true) log[method](metadata, body);
104
105
  otelLogger().emit({
105
106
  body,
107
+ timestamp: date,
106
108
  severityNumber: (0, _effect_opentelemetry_OtelLogger.logLevelToSeverityNumber)(logLevel),
107
109
  severityText: logLevel,
108
110
  attributes: (0, autotel.flattenToAttributes)({
package/dist/index.js CHANGED
@@ -61,11 +61,12 @@ function loggerLayer(options) {
61
61
  ...options.pretty ? { pretty: options.pretty } : {}
62
62
  });
63
63
  const otelLogger = () => logs.getLogger(options.serviceName, options.serviceVersion);
64
- return Logger.layer([Logger.make(({ cause, fiber, logLevel, message }) => {
64
+ return Logger.layer([Logger.make(({ cause, date, fiber, logLevel, message }) => {
65
65
  const method = LEVEL_TO_METHOD[logLevel];
66
66
  if (!method) return;
67
67
  const parts = Array.isArray(message) ? message : [message];
68
68
  const metadata = { ...fiber.getRef(References.CurrentLogAnnotations) };
69
+ for (const [label, start] of fiber.getRef(References.CurrentLogSpans)) metadata[`logSpan.${label}`] = date.getTime() - start;
69
70
  const errors = parts.filter((part) => part instanceof Error);
70
71
  if (cause.reasons.length > 0) metadata.err = Cause.pretty(cause);
71
72
  else if (errors.length > 0) metadata.err = errors.map((error) => error.stack ?? String(error));
@@ -73,6 +74,7 @@ function loggerLayer(options) {
73
74
  if (options.console ?? true) log[method](metadata, body);
74
75
  otelLogger().emit({
75
76
  body,
77
+ timestamp: date,
76
78
  severityNumber: logLevelToSeverityNumber(logLevel),
77
79
  severityText: logLevel,
78
80
  attributes: flattenToAttributes({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-effect",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
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",
@@ -55,7 +55,7 @@
55
55
  "@opentelemetry/api-logs": "^0.222.0",
56
56
  "@opentelemetry/sdk-logs": "^0.222.0",
57
57
  "@types/node": "^26.1.2",
58
- "autotel": "7.7.0",
58
+ "autotel": "7.7.1",
59
59
  "effect": "4.0.0-rc.112",
60
60
  "rimraf": "^6.1.3",
61
61
  "tsdown": "^0.22.14",