1import { assert, describe, it } from "@effect/vitest"
2import { ConfigProvider, Effect } from "effect"
3import { OtlpResource } from "effect/observability"
4
5const attributesRecord = (resource: OtlpResource.Resource): Record<string, string | null | undefined> =>
6 Object.fromEntries(resource.attributes.map((attribute) => [attribute.key, attribute.value.stringValue]))
7
8describe("OtlpResource", () => {
9 describe("fromConfig", () => {
10 it.effect("decodes percent-encoded OTEL_RESOURCE_ATTRIBUTES", () =>
11 Effect.gen(function*() {
12 const resource = yield* OtlpResource.fromConfig()
13 const attributes = Object.fromEntries(
14 resource.attributes.map((attribute) => [attribute.key, attribute.value.stringValue])
15 )
16
17 assert.strictEqual(attributes.message, "hello world")
18 assert.strictEqual(attributes.comma, "comma,value")
19 }).pipe(
20 Effect.provideService(
21 ConfigProvider.ConfigProvider,
22 ConfigProvider.fromEnv({
23 env: {
24 OTEL_SERVICE_NAME: "repro",
25 OTEL_RESOURCE_ATTRIBUTES: "message=hello%20world,comma=comma%2Cvalue"
26 }
27 })
28 )
29 ))
30
31 it.effect("uses explicit service options before attributes and environment variables", () =>
32 Effect.gen(function*() {
33 const resource = yield* OtlpResource.fromConfig({
34 serviceName: "explicit-service",
35 serviceVersion: "explicit-version",
36 attributes: {
37 "custom.attribute": "explicit",
38 "service.name": "explicit-attribute-service",
39 "service.version": "explicit-attribute-version"
40 }
41 })
42
43 assert.deepStrictEqual(attributesRecord(resource), {
44 "custom.attribute": "explicit",
45 "service.name": "explicit-service",
46 "service.version": "explicit-version"
47 })
48 }).pipe(
49 Effect.provideService(
50 ConfigProvider.ConfigProvider,
51 ConfigProvider.fromEnv({
52 env: {
53 OTEL_SERVICE_NAME: "env-service",
54 OTEL_SERVICE_VERSION: "env-version",
55 OTEL_RESOURCE_ATTRIBUTES: "service.name=env-attribute-service,service.version=env-attribute-version"
56 }
57 })
58 )
59 ))
60
61 it.effect("uses explicit attributes before environment variables", () =>
62 Effect.gen(function*() {
63 const resource = yield* OtlpResource.fromConfig({
64 attributes: {
65 "custom.attribute": "explicit",
66 "service.name": "explicit-attribute-service",
67 "service.version": "explicit-attribute-version"
68 }
69 })
70
71 assert.deepStrictEqual(attributesRecord(resource), {
72 "custom.attribute": "explicit",
73 "service.name": "explicit-attribute-service",
74 "service.version": "explicit-attribute-version"
75 })
76 }).pipe(
77 Effect.provideService(
78 ConfigProvider.ConfigProvider,
79 ConfigProvider.fromEnv({
80 env: {
81 OTEL_SERVICE_NAME: "env-service",
82 OTEL_SERVICE_VERSION: "env-version",
83 OTEL_RESOURCE_ATTRIBUTES:
84 "service.name=env-attribute-service,service.version=env-attribute-version,custom.attribute=env"
85 }
86 })
87 )
88 ))
89
90 it.effect("uses dedicated service variables before OTEL resource attributes", () =>
91 Effect.gen(function*() {
92 const resource = yield* OtlpResource.fromConfig()
93
94 assert.deepStrictEqual(attributesRecord(resource), {
95 "service.name": "env-service",
96 "service.version": "env-version"
97 })
98 }).pipe(
99 Effect.provideService(
100 ConfigProvider.ConfigProvider,
101 ConfigProvider.fromEnv({
102 env: {
103 OTEL_SERVICE_NAME: "env-service",
104 OTEL_SERVICE_VERSION: "env-version",
105 OTEL_RESOURCE_ATTRIBUTES: "service.name=env-attribute-service,service.version=env-attribute-version"
106 }
107 })
108 )
109 ))
110
111 it.effect("omits service.version when it is not configured", () =>
112 Effect.gen(function*() {
113 const resource = yield* OtlpResource.fromConfig({
114 serviceName: "explicit-service"
115 })
116
117 assert.deepStrictEqual(attributesRecord(resource), {
118 "service.name": "explicit-service"
119 })
120 }).pipe(
121 Effect.provideService(
122 ConfigProvider.ConfigProvider,
123 ConfigProvider.fromEnv({
124 env: {}
125 })
126 )
127 ))
128 })
129
130 describe("unknownToAttributeValue", () => {
131 it("preserves bigint attribute precision", () => {
132 const input = 9_007_199_254_740_993n
133 const output = OtlpResource.unknownToAttributeValue(input)
134
135 assert.strictEqual(String(output.intValue), input.toString())
136 })
137 })
138})