@playwright-opentelemetry/trace-api
v0.3.4
Published
H3-based API library for storing and serving Playwright OpenTelemetry traces in S3-compatible storage.
Downloads
1,062
Maintainers
Readme
@playwright-opentelemetry/trace-api
H3-based API library for storing and serving Playwright OpenTelemetry traces in S3-compatible object storage.
Introduction
The Trace API is a customizable library that can be deployed to Cloudflare Workers, Deno, Bun, Node.js, or any platform supporting web-standard Request/Response handlers. It provides endpoints for writing OTLP trace data and Playwright test artifacts, and serves them in a format compatible with the trace viewer.
Usage
Basic Usage
import { createTraceApi } from '@playwright-opentelemetry/trace-api';
const api = createTraceApi({
storage: {
bucket: 'my-traces',
endpoint: 'https://xxx.r2.cloudflarestorage.com',
accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
region: 'auto',
},
});
export default {
fetch: api.fetch,
};Low-Level Building Blocks with Authentication
For maximum flexibility, compose your own API using individual handlers:
import { H3, getHeader, createError } from 'h3';
import {
createS3Storage,
createOtlpHandler,
createPlaywrightHandler,
createViewerHandler,
OTLP_TRACES_WRITE_PATH,
PLAYWRIGHT_REPORTER_WRITE_PATH,
TRACE_VIEWER_READ_PATH,
} from '@playwright-opentelemetry/trace-api';
const storage = createS3Storage({
bucket: 'my-traces',
endpoint: env.R2_ENDPOINT,
accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
});
const app = new H3();
// Authentication middleware for write endpoints
const authMiddleware = async (event) => {
const token = getHeader(event, 'authorization')?.replace('Bearer ', '');
if (!token || !await validateToken(token)) {
throw createError({ statusCode: 401, message: 'Unauthorized' });
}
};
// Apply auth to write endpoints
app.use(OTLP_TRACES_WRITE_PATH, authMiddleware);
app.use(PLAYWRIGHT_REPORTER_WRITE_PATH, authMiddleware);
// Add handlers
// /v1/traces/
app.post(OTLP_TRACES_WRITE_PATH, createOtlpHandler(storage));
// /otel-playwright-reporter/**
app.put(PLAYWRIGHT_REPORTER_WRITE_PATH, createPlaywrightHandler(storage));
// /otel-trace-viewer/**
app.get(TRACE_VIEWER_READ_PATH, createViewerHandler(storage));
export default {
fetch: app.fetch,
};Other Runtimes
Deno:
import { createTraceApi } from '@playwright-opentelemetry/trace-api';
const api = createTraceApi({ storage: { ... } });
Deno.serve({ port: 3000 }, api.fetch);Bun:
import { createTraceApi } from '@playwright-opentelemetry/trace-api';
const api = createTraceApi({ storage: { ... } });
export default {
port: 3000,
fetch: api.fetch,
};Node.js:
import { serve } from 'h3/node';
import { createTraceApi } from '@playwright-opentelemetry/trace-api';
const api = createTraceApi({ storage: { ... } });
serve(api, { port: 3000 });API Reference
Configuration
interface TraceApiConfig {
storage: {
bucket: string;
endpoint: string;
accessKeyId: string;
secretAccessKey: string;
region?: string; // Default: 'auto'
};
}Endpoints
Write Endpoints:
POST /v1/traces
Content-Type: application/json
Body: Standard OTLP JSON payloadWrites OTLP spans to traces/{traceId}/opentelemetry-protocol/{serviceName}.json.
PUT /otel-playwright-reporter/test.json
X-Trace-Id: {traceId}
Body: test.json contentWrites test metadata to traces/{traceId}/test.json.
PUT /otel-playwright-reporter/screenshots/{filename}
X-Trace-Id: {traceId}
Body: JPEG image dataWrites screenshots to traces/{traceId}/screenshots/{filename}.
Read Endpoints:
GET /otel-trace-viewer/{traceId}/test.json
GET /otel-trace-viewer/{traceId}/opentelemetry-protocol
GET /otel-trace-viewer/{traceId}/opentelemetry-protocol/{file}.json
GET /otel-trace-viewer/{traceId}/screenshots
GET /otel-trace-viewer/{traceId}/screenshots/{filename}Serves trace data in the format expected by the trace viewer.
Storage Setup
Configure your S3-compatible bucket with a lifecycle rule to expire traces after the desired retention period.
AWS S3
aws s3api put-bucket-lifecycle-configuration \
--bucket my-traces \
--lifecycle-configuration '{
"Rules": [{
"ID": "ExpireTraces",
"Status": "Enabled",
"Filter": { "Prefix": "traces/" },
"Expiration": { "Days": 30 }
}]
}'Cloudflare R2
wrangler r2 bucket lifecycle set my-traces --rules '[{
"id": "expire-traces",
"enabled": true,
"conditions": { "prefix": "traces/" },
"deleteObjectsTransition": { "daysAfterUpload": 30 }
}]'Storage Structure
s3://bucket/
└── traces/
└── {traceId}/
├── test.json
├── opentelemetry-protocol/
│ ├── playwright-opentelemetry.json
│ └── {serviceName}.json
└── screenshots/
└── {pageId}-{timestamp}.jpeg