Buckets:
| import { afterEach, describe, expect, test } from "bun:test" | |
| import { NodeFileSystem } from "@effect/platform-node" | |
| import { Effect, Layer, Logger } from "effect" | |
| import fs from "fs/promises" | |
| import os from "os" | |
| import path from "path" | |
| import { fileLogger } from "../../src/observability/logging" | |
| import { resource } from "../../src/observability/otlp" | |
| const otelResourceAttributes = process.env.OTEL_RESOURCE_ATTRIBUTES | |
| const opencodeClient = process.env.OPENCODE_CLIENT | |
| afterEach(() => { | |
| if (otelResourceAttributes === undefined) delete process.env.OTEL_RESOURCE_ATTRIBUTES | |
| else process.env.OTEL_RESOURCE_ATTRIBUTES = otelResourceAttributes | |
| if (opencodeClient === undefined) delete process.env.OPENCODE_CLIENT | |
| else process.env.OPENCODE_CLIENT = opencodeClient | |
| }) | |
| describe("resource", () => { | |
| test("parses and decodes OTEL resource attributes", () => { | |
| process.env.OTEL_RESOURCE_ATTRIBUTES = | |
| "service.namespace=anomalyco,team=platform%2Cobservability,label=hello%3Dworld,key%2Fname=value%20here" | |
| expect(resource().attributes).toMatchObject({ | |
| "service.namespace": "anomalyco", | |
| team: "platform,observability", | |
| label: "hello=world", | |
| "key/name": "value here", | |
| }) | |
| }) | |
| test("drops OTEL resource attributes when any entry is invalid", () => { | |
| process.env.OTEL_RESOURCE_ATTRIBUTES = "service.namespace=anomalyco,broken" | |
| expect(resource().attributes["service.namespace"]).toBeUndefined() | |
| expect(resource().attributes["opencode.client"]).toBeDefined() | |
| }) | |
| test("keeps built-in attributes when env values conflict", () => { | |
| process.env.OPENCODE_CLIENT = "cli" | |
| process.env.OTEL_RESOURCE_ATTRIBUTES = | |
| "opencode.client=web,service.instance.id=override,service.namespace=anomalyco" | |
| expect(resource().attributes).toMatchObject({ | |
| "opencode.client": "cli", | |
| "service.namespace": "anomalyco", | |
| }) | |
| expect(resource().attributes["service.instance.id"]).not.toBe("override") | |
| expect(resource().attributes["opencode.run"]).toMatch(/^[0-9a-f]{8}$/) | |
| }) | |
| }) | |
| test("file logger appends concurrent runs with a run on every line", async () => { | |
| const dir = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-log-test-")) | |
| await using _ = { | |
| async [Symbol.asyncDispose]() { | |
| await fs.rm(dir, { recursive: true, force: true }) | |
| }, | |
| } | |
| const file = path.join(dir, "opencode.log") | |
| const write = (runID: string) => | |
| Effect.forEach( | |
| Array.from({ length: 50 }, (_, index) => index), | |
| (index) => Effect.logInfo(`entry-${index}`), | |
| ).pipe( | |
| Effect.provide(Logger.layer([fileLogger(file, runID)]).pipe(Layer.provide(NodeFileSystem.layer), Layer.orDie)), | |
| Effect.scoped, | |
| ) | |
| await Effect.runPromise(Effect.all([write("run-a"), write("run-b")], { concurrency: "unbounded" })) | |
| const lines = (await Bun.file(file).text()).trim().split("\n") | |
| expect(lines).toHaveLength(100) | |
| expect(lines.filter((line) => line.includes("run=run-a"))).toHaveLength(50) | |
| expect(lines.filter((line) => line.includes("run=run-b"))).toHaveLength(50) | |
| expect(lines.every((line) => line.startsWith("timestamp=") && line.includes(" level=INFO "))).toBe(true) | |
| expect(lines.every((line) => !line.includes(" fiber="))).toBe(true) | |
| expect(lines.every((line) => !line.startsWith("{"))).toBe(true) | |
| }) | |
| test("file logger flattens nested objects", async () => { | |
| const dir = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-log-test-")) | |
| await using _ = { | |
| async [Symbol.asyncDispose]() { | |
| await fs.rm(dir, { recursive: true, force: true }) | |
| }, | |
| } | |
| const file = path.join(dir, "opencode.log") | |
| await Effect.logInfo("request complete", { | |
| request: { method: "GET", timing: { duration: 42 } }, | |
| tags: ["api", "test"], | |
| }).pipe( | |
| Effect.annotateLogs({ session: { id: "session-1" } }), | |
| Effect.provide(Logger.layer([fileLogger(file, "run-a")]).pipe(Layer.provide(NodeFileSystem.layer), Layer.orDie)), | |
| Effect.scoped, | |
| Effect.runPromise, | |
| ) | |
| const line = (await Bun.file(file).text()).trim() | |
| expect(line).toContain('message="request complete"') | |
| expect(line).toContain("request.method=GET") | |
| expect(line).toContain("request.timing.duration=42") | |
| expect(line).toContain('tags="[\\\"api\\\",\\\"test\\\"]"') | |
| expect(line).toContain("session.id=session-1") | |
| expect(line).not.toContain("request={") | |
| }) | |
Xet Storage Details
- Size:
- 4.34 kB
- Xet hash:
- eda40ef7c7d247e8cfe19c9434a7b7d35b55d72134a7cb7c94427d78e3264552
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.