@effect/opentelemetry 0.42.9 → 0.43.1

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.
Files changed (48) hide show
  1. package/Logger/package.json +6 -0
  2. package/dist/cjs/Logger.js +85 -0
  3. package/dist/cjs/Logger.js.map +1 -0
  4. package/dist/cjs/NodeSdk.js +8 -4
  5. package/dist/cjs/NodeSdk.js.map +1 -1
  6. package/dist/cjs/Resource.js +14 -8
  7. package/dist/cjs/Resource.js.map +1 -1
  8. package/dist/cjs/WebSdk.js +7 -3
  9. package/dist/cjs/WebSdk.js.map +1 -1
  10. package/dist/cjs/index.js +3 -1
  11. package/dist/cjs/internal/tracer.js +6 -24
  12. package/dist/cjs/internal/tracer.js.map +1 -1
  13. package/dist/cjs/internal/utils.js +35 -0
  14. package/dist/cjs/internal/utils.js.map +1 -0
  15. package/dist/dts/Logger.d.ts +39 -0
  16. package/dist/dts/Logger.d.ts.map +1 -0
  17. package/dist/dts/NodeSdk.d.ts +4 -1
  18. package/dist/dts/NodeSdk.d.ts.map +1 -1
  19. package/dist/dts/Resource.d.ts +9 -0
  20. package/dist/dts/Resource.d.ts.map +1 -1
  21. package/dist/dts/WebSdk.d.ts +4 -1
  22. package/dist/dts/WebSdk.d.ts.map +1 -1
  23. package/dist/dts/index.d.ts +4 -0
  24. package/dist/dts/index.d.ts.map +1 -1
  25. package/dist/dts/internal/utils.d.ts +2 -0
  26. package/dist/dts/internal/utils.d.ts.map +1 -0
  27. package/dist/esm/Logger.js +74 -0
  28. package/dist/esm/Logger.js.map +1 -0
  29. package/dist/esm/NodeSdk.js +8 -4
  30. package/dist/esm/NodeSdk.js.map +1 -1
  31. package/dist/esm/Resource.js +11 -6
  32. package/dist/esm/Resource.js.map +1 -1
  33. package/dist/esm/WebSdk.js +7 -3
  34. package/dist/esm/WebSdk.js.map +1 -1
  35. package/dist/esm/index.js +4 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/internal/tracer.js +1 -19
  38. package/dist/esm/internal/tracer.js.map +1 -1
  39. package/dist/esm/internal/utils.js +23 -0
  40. package/dist/esm/internal/utils.js.map +1 -0
  41. package/package.json +13 -2
  42. package/src/Logger.ts +111 -0
  43. package/src/NodeSdk.ts +24 -15
  44. package/src/Resource.ts +20 -9
  45. package/src/WebSdk.ts +23 -10
  46. package/src/index.ts +5 -0
  47. package/src/internal/tracer.ts +1 -22
  48. package/src/internal/utils.ts +31 -0
package/src/NodeSdk.ts CHANGED
@@ -2,13 +2,16 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import type * as Resources from "@opentelemetry/resources"
5
+ import type { LoggerProviderConfig, LogRecordProcessor } from "@opentelemetry/sdk-logs"
5
6
  import type { MetricReader } from "@opentelemetry/sdk-metrics"
6
7
  import type { SpanProcessor, TracerConfig } from "@opentelemetry/sdk-trace-base"
7
8
  import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node"
8
9
  import type { NonEmptyReadonlyArray } from "effect/Array"
9
10
  import * as Effect from "effect/Effect"
10
- import type { LazyArg } from "effect/Function"
11
+ import { constant, type LazyArg } from "effect/Function"
11
12
  import * as Layer from "effect/Layer"
13
+ import { isNonEmpty } from "./internal/utils.js"
14
+ import * as Logger from "./Logger.js"
12
15
  import * as Metrics from "./Metrics.js"
13
16
  import * as Resource from "./Resource.js"
14
17
  import * as Tracer from "./Tracer.js"
@@ -21,6 +24,8 @@ export interface Configuration {
21
24
  readonly spanProcessor?: SpanProcessor | ReadonlyArray<SpanProcessor> | undefined
22
25
  readonly tracerConfig?: Omit<TracerConfig, "resource"> | undefined
23
26
  readonly metricReader?: MetricReader | ReadonlyArray<MetricReader> | undefined
27
+ readonly logRecordProcessor?: LogRecordProcessor | ReadonlyArray<LogRecordProcessor> | undefined
28
+ readonly loggerProviderConfig?: Omit<LoggerProviderConfig, "resource"> | undefined
24
29
  readonly resource?: {
25
30
  readonly serviceName: string
26
31
  readonly serviceVersion?: string
@@ -83,20 +88,24 @@ export const layer: {
83
88
  ? evaluate as Effect.Effect<Configuration>
84
89
  : Effect.sync(evaluate),
85
90
  (config) => {
86
- const ResourceLive = config.resource === undefined
87
- ? Resource.layerFromEnv()
88
- : Resource.layer(config.resource)
89
- const TracerLive =
90
- config.spanProcessor && !(Array.isArray(config.spanProcessor) && config.spanProcessor.length === 0) ?
91
- Tracer.layer.pipe(
92
- Layer.provide(layerTracerProvider(config.spanProcessor as any, config.tracerConfig))
93
- )
94
- : Layer.empty
95
- const MetricsLive =
96
- config.metricReader && !(Array.isArray(config.metricReader) && config.metricReader.length === 0)
97
- ? Metrics.layer(() => config.metricReader as any)
98
- : Layer.empty
99
- return Layer.merge(TracerLive, MetricsLive).pipe(
91
+ const ResourceLive = Resource.layerFromEnv(config.resource && Resource.configToAttributes(config.resource))
92
+
93
+ const TracerLive = isNonEmpty(config.spanProcessor)
94
+ ? Layer.provide(Tracer.layer, layerTracerProvider(config.spanProcessor, config.tracerConfig))
95
+ : Layer.empty
96
+
97
+ const MetricsLive = isNonEmpty(config.metricReader)
98
+ ? Metrics.layer(constant(config.metricReader))
99
+ : Layer.empty
100
+
101
+ const LoggerLive = isNonEmpty(config.logRecordProcessor)
102
+ ? Layer.provide(
103
+ Logger.layerLoggerAdd,
104
+ Logger.layerLoggerProvider(config.logRecordProcessor, config.loggerProviderConfig)
105
+ )
106
+ : Layer.empty
107
+
108
+ return Layer.mergeAll(TracerLive, MetricsLive, LoggerLive).pipe(
100
109
  Layer.provideMerge(ResourceLive)
101
110
  )
102
111
  }
package/src/Resource.ts CHANGED
@@ -39,22 +39,33 @@ export const layer = (config: {
39
39
  readonly serviceName: string
40
40
  readonly serviceVersion?: string
41
41
  readonly attributes?: Resources.ResourceAttributes
42
- }) => {
42
+ }) =>
43
+ Layer.succeed(
44
+ Resource,
45
+ new Resources.Resource(configToAttributes(config))
46
+ )
47
+
48
+ /**
49
+ * @since 1.0.0
50
+ * @category config
51
+ */
52
+ export const configToAttributes = (options: {
53
+ readonly serviceName: string
54
+ readonly serviceVersion?: string
55
+ readonly attributes?: Resources.ResourceAttributes
56
+ }): Record<string, string> => {
43
57
  const attributes: Record<string, string> = {
44
- ...(config.attributes ?? undefined),
45
- [SEMRESATTRS_SERVICE_NAME]: config.serviceName,
58
+ ...(options.attributes ?? undefined),
59
+ [SEMRESATTRS_SERVICE_NAME]: options.serviceName,
46
60
  [SEMRESATTRS_TELEMETRY_SDK_NAME]: "@effect/opentelemetry",
47
61
  [SEMRESATTRS_TELEMETRY_SDK_LANGUAGE]: typeof (globalThis as any).document === "undefined"
48
62
  ? TELEMETRYSDKLANGUAGEVALUES_NODEJS
49
63
  : TELEMETRYSDKLANGUAGEVALUES_WEBJS
50
64
  }
51
- if (config.serviceVersion) {
52
- attributes[SEMRESATTRS_SERVICE_VERSION] = config.serviceVersion
65
+ if (options.serviceVersion) {
66
+ attributes[SEMRESATTRS_SERVICE_VERSION] = options.serviceVersion
53
67
  }
54
- return Layer.succeed(
55
- Resource,
56
- new Resources.Resource(attributes)
57
- )
68
+ return attributes
58
69
  }
59
70
 
60
71
  /**
package/src/WebSdk.ts CHANGED
@@ -2,13 +2,16 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import type * as Resources from "@opentelemetry/resources"
5
+ import type { LoggerProviderConfig, LogRecordProcessor } from "@opentelemetry/sdk-logs"
5
6
  import type { MetricReader } from "@opentelemetry/sdk-metrics"
6
7
  import type { SpanProcessor, TracerConfig } from "@opentelemetry/sdk-trace-base"
7
8
  import { WebTracerProvider } from "@opentelemetry/sdk-trace-web"
8
9
  import type { NonEmptyReadonlyArray } from "effect/Array"
9
10
  import * as Effect from "effect/Effect"
10
- import type { LazyArg } from "effect/Function"
11
+ import { constant, type LazyArg } from "effect/Function"
11
12
  import * as Layer from "effect/Layer"
13
+ import { isNonEmpty } from "./internal/utils.js"
14
+ import * as Logger from "./Logger.js"
12
15
  import * as Metrics from "./Metrics.js"
13
16
  import * as Resource from "./Resource.js"
14
17
  import * as Tracer from "./Tracer.js"
@@ -21,6 +24,8 @@ export interface Configuration {
21
24
  readonly spanProcessor?: SpanProcessor | ReadonlyArray<SpanProcessor> | undefined
22
25
  readonly tracerConfig?: Omit<TracerConfig, "resource">
23
26
  readonly metricReader?: MetricReader | ReadonlyArray<MetricReader> | undefined
27
+ readonly logRecordProcessor?: LogRecordProcessor | ReadonlyArray<LogRecordProcessor> | undefined
28
+ readonly loggerProviderConfig?: Omit<LoggerProviderConfig, "resource"> | undefined
24
29
  readonly resource: {
25
30
  readonly serviceName: string
26
31
  readonly serviceVersion?: string
@@ -84,15 +89,23 @@ export const layer: {
84
89
  : Effect.sync(evaluate),
85
90
  (config) => {
86
91
  const ResourceLive = Resource.layer(config.resource)
87
- const TracerLive =
88
- config.spanProcessor && !(Array.isArray(config.spanProcessor) && config.spanProcessor.length === 0) ?
89
- Tracer.layer.pipe(Layer.provide(layerTracerProvider(config.spanProcessor as any, config.tracerConfig)))
90
- : Layer.effectDiscard(Effect.void)
91
- const MetricsLive =
92
- config.metricReader && !(Array.isArray(config.metricReader) && config.metricReader.length === 0)
93
- ? Metrics.layer(() => config.metricReader as any)
94
- : Layer.effectDiscard(Effect.void)
95
- return Layer.merge(TracerLive, MetricsLive).pipe(
92
+
93
+ const TracerLive = isNonEmpty(config.spanProcessor)
94
+ ? Layer.provide(Tracer.layer, layerTracerProvider(config.spanProcessor, config.tracerConfig))
95
+ : Layer.empty
96
+
97
+ const LoggerLive = isNonEmpty(config.logRecordProcessor)
98
+ ? Layer.provide(
99
+ Logger.layerLoggerAdd,
100
+ Logger.layerLoggerProvider(config.logRecordProcessor, config.loggerProviderConfig)
101
+ )
102
+ : Layer.empty
103
+
104
+ const MetricsLive = isNonEmpty(config.metricReader)
105
+ ? Metrics.layer(constant(config.metricReader))
106
+ : Layer.empty
107
+
108
+ return Layer.mergeAll(TracerLive, MetricsLive, LoggerLive).pipe(
96
109
  Layer.provideMerge(ResourceLive)
97
110
  )
98
111
  }
package/src/index.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ export * as Logger from "./Logger.js"
5
+
1
6
  /**
2
7
  * @since 1.0.0
3
8
  */
@@ -4,12 +4,12 @@ import * as Context from "effect/Context"
4
4
  import * as Effect from "effect/Effect"
5
5
  import type { Exit } from "effect/Exit"
6
6
  import { dual } from "effect/Function"
7
- import * as Inspectable from "effect/Inspectable"
8
7
  import * as Layer from "effect/Layer"
9
8
  import * as Option from "effect/Option"
10
9
  import * as EffectTracer from "effect/Tracer"
11
10
  import { Resource } from "../Resource.js"
12
11
  import type { OtelTraceFlags, OtelTracer, OtelTracerProvider, OtelTraceState } from "../Tracer.js"
12
+ import { nanosToHrTime, recordToAttributes, unknownToAttributeValue } from "./utils.js"
13
13
 
14
14
  const OtelSpanTypeId = Symbol.for("@effect/opentelemetry/Tracer/OtelSpan")
15
15
 
@@ -257,11 +257,6 @@ export const layer = layerWithoutOtelTracer.pipe(
257
257
  // utils
258
258
  // -------------------------------------------------------------------------------------
259
259
 
260
- const bigint1e9 = 1_000_000_000n
261
- const nanosToHrTime = (timestamp: bigint): OtelApi.HrTime => {
262
- return [Number(timestamp / bigint1e9), Number(timestamp % bigint1e9)]
263
- }
264
-
265
260
  const createTraceState = Option.liftThrowable(OtelApi.createTraceState)
266
261
 
267
262
  const populateContext = (
@@ -300,22 +295,6 @@ const extractTraceTag = <I, S>(
300
295
  () => Context.getOption(parent.context, tag)
301
296
  )
302
297
 
303
- const recordToAttributes = (value: Record<string, unknown>): OtelApi.Attributes => {
304
- return Object.entries(value).reduce((acc, [key, value]) => {
305
- acc[key] = unknownToAttributeValue(value)
306
- return acc
307
- }, {} as OtelApi.Attributes)
308
- }
309
-
310
- const unknownToAttributeValue = (value: unknown): OtelApi.AttributeValue => {
311
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
312
- return value
313
- } else if (typeof value === "bigint") {
314
- return Number(value)
315
- }
316
- return Inspectable.toStringUnknown(value)
317
- }
318
-
319
298
  /** @internal */
320
299
  export const withSpanContext = dual<
321
300
  (
@@ -0,0 +1,31 @@
1
+ import type * as OtelApi from "@opentelemetry/api"
2
+ import type { NonEmptyReadonlyArray } from "effect/Array"
3
+ import * as Inspectable from "effect/Inspectable"
4
+
5
+ const bigint1e9 = 1_000_000_000n
6
+
7
+ /** @internal */
8
+ export const nanosToHrTime = (timestamp: bigint): OtelApi.HrTime => {
9
+ return [Number(timestamp / bigint1e9), Number(timestamp % bigint1e9)]
10
+ }
11
+
12
+ /** @internal */
13
+ export const recordToAttributes = (value: Record<string, unknown>): OtelApi.Attributes =>
14
+ Object.entries(value).reduce((acc, [key, value]) => {
15
+ acc[key] = unknownToAttributeValue(value)
16
+ return acc
17
+ }, {} as OtelApi.Attributes)
18
+
19
+ /** @internal */
20
+ export const unknownToAttributeValue = (value: unknown): OtelApi.AttributeValue => {
21
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
22
+ return value
23
+ } else if (typeof value === "bigint") {
24
+ return Number(value)
25
+ }
26
+ return Inspectable.toStringUnknown(value)
27
+ }
28
+
29
+ /** @internal */
30
+ export const isNonEmpty = <A>(a: A | ReadonlyArray<A> | undefined): a is A | NonEmptyReadonlyArray<A> =>
31
+ a !== undefined && !(Array.isArray(a) && a.length === 0)