Skip to content

Commit 6fa1410

Browse files
committed
Update API signatures, fix span_kind attribute
1 parent 3e3472b commit 6fa1410

File tree

7 files changed

+60
-30
lines changed

7 files changed

+60
-30
lines changed

.changeset/spotty-pens-float.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@pydantic/logfire-cf-workers": minor
3+
"@pydantic/logfire-api": minor
4+
"logfire": minor
5+
---
6+
7+
API updates, fixes for span kind

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,35 @@ npm install @pydantic/logfire-cf-workers @pydantic/logfire-api
6969
```
7070
Next, add `compatibility_flags = [ "nodejs_compat" ]` to your wrangler.toml or `"compatibility_flags": ["nodejs_compat"]` if you're using `wrangler.jsonc`.
7171

72-
Add your [Logfire write token](https://logfire.pydantic.dev/docs/how-to-guides/create-write-tokens/) to your `.dev.vars` file. Check the [Cloudflare documentation for further details on how to manage and deploy the secrets](https://developers.cloudflare.com/workers/configuration/secrets/).
72+
Add your [Logfire write token](https://logfire.pydantic.dev/docs/how-to-guides/create-write-tokens/) to your `.dev.vars` file.
7373

7474
```sh
7575
LOGFIRE_TOKEN=your-write-token
7676
```
7777

78+
For the production deployment, check the [Cloudflare documentation for further details on how to manage and deploy the secrets](https://developers.cloudflare.com/workers/configuration/secrets/).
79+
80+
One way to do that is through the `npx wrangler` command:
81+
82+
```sh
83+
npx wrangler secret put LOGFIRE_TOKEN
84+
```
85+
86+
7887
Next, add the necessary instrumentation around your handler. The `tracerConfig` function will extract your write token from the `env` object and provide the necessary configuration for the instrumentation:
7988

89+
8090
```ts
8191
import * as logfire from '@pydantic/logfire-api';
8292
import { instrument } from '@pydantic/logfire-cf-workers';
8393

94+
8495
const handler = {
85-
async fetch(): Promise<Response> {
86-
logfire.info('info span from inside the worker body');
87-
return new Response('Hello World!');
88-
},
89-
} satisfies ExportedHandler;
96+
async fetch(): promise<response> {
97+
logfire.info('info span from inside the worker body');
98+
return new response('hello world!');
99+
},
100+
} satisfies exportedHandler;
90101

91102
export default instrument(handler, {
92103
serviceName: 'cloudflare-worker',

examples/nextjs/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as logfire from '@pydantic/logfire-api'
22

33
/** Add your relevant code here for the issue to reproduce */
44
export default async function Home() {
5-
return logfire.startActiveSpan(logfire.Level.Info, 'Info parent span', {}, {}, async () => {
5+
return logfire.span('Info parent span', {}, { level: logfire.Level.Info }, async () => {
66
logfire.info('child span');
77
return <div>Hello</div>;
88
})

packages/logfire-api/src/index.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
/* eslint-disable perfectionist/sort-objects */
2-
import { context as ContextAPI, Span, SpanStatusCode, trace as TraceAPI } from '@opentelemetry/api'
2+
import { context as ContextAPI, Span, SpanOptions, SpanStatusCode, trace as TraceAPI } from '@opentelemetry/api'
33
import { ATTR_EXCEPTION_MESSAGE, ATTR_EXCEPTION_STACKTRACE } from '@opentelemetry/semantic-conventions'
44

55
export * from './AttributeScrubber'
66
export { serializeAttributes } from './serializeAttributes'
77

88
const DEFAULT_OTEL_SCOPE = 'logfire'
99

10-
export interface LogOptions {
11-
tags?: string[]
12-
}
13-
1410
export interface LogfireApiConfigOptions {
1511
otelScope?: string
1612
}
@@ -27,8 +23,15 @@ export const Level = {
2723

2824
export type LogFireLevel = (typeof Level)[keyof typeof Level]
2925

26+
export interface LogOptions {
27+
level?: LogFireLevel
28+
log?: true
29+
tags?: string[]
30+
}
31+
3032
const LOGFIRE_ATTRIBUTES_NAMESPACE = 'logfire'
3133
const ATTRIBUTES_LEVEL_KEY = `${LOGFIRE_ATTRIBUTES_NAMESPACE}.level_num`
34+
const ATTRIBUTES_SPAN_TYPE_KEY = `${LOGFIRE_ATTRIBUTES_NAMESPACE}.span_type`
3235
export const ATTRIBUTES_TAGS_KEY = `${LOGFIRE_ATTRIBUTES_NAMESPACE}.tags`
3336

3437
const currentLogfireApiConfig: LogfireApiConfigOptions = {}
@@ -53,14 +56,19 @@ const logfireApiConfig = {
5356
},
5457
}
5558

56-
function startSpan(level: LogFireLevel, message: string, attributes: Record<string, unknown> = {}, { tags = [] }: LogOptions = {}): Span {
59+
export function startSpan(
60+
message: string,
61+
attributes: Record<string, unknown> = {},
62+
{ log, tags = [], level = Level.Info }: LogOptions = {}
63+
): Span {
5764
const span = logfireApiConfig.tracer.startSpan(
5865
message,
5966
{
6067
attributes: {
6168
...attributes,
6269
[ATTRIBUTES_LEVEL_KEY]: level,
6370
[ATTRIBUTES_TAGS_KEY]: Array.from(new Set(tags).values()),
71+
[ATTRIBUTES_SPAN_TYPE_KEY]: log ? 'log' : 'span',
6472
},
6573
},
6674
logfireApiConfig.context
@@ -69,11 +77,10 @@ function startSpan(level: LogFireLevel, message: string, attributes: Record<stri
6977
return span
7078
}
7179

72-
export function startActiveSpan<F extends (span: Span) => unknown>(
73-
level: LogFireLevel,
80+
export function span<F extends (span: Span) => unknown>(
7481
message: string,
7582
attributes: Record<string, unknown> = {},
76-
{ tags = [] }: LogOptions = {},
83+
{ tags = [], level = Level.Info }: LogOptions = {},
7784
callback: F
7885
) {
7986
return logfireApiConfig.tracer.startActiveSpan<F>(
@@ -89,40 +96,40 @@ export function startActiveSpan<F extends (span: Span) => unknown>(
8996
)
9097
}
9198

92-
export function log(level: LogFireLevel, message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
93-
startSpan(level, message, attributes, options).end()
99+
export function log(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
100+
startSpan(message, attributes, { ...options, log: true }).end()
94101
}
95102

96103
export function debug(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
97-
log(Level.Debug, message, attributes, options)
104+
log(message, attributes, { ...options, level: Level.Debug })
98105
}
99106

100107
export function info(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
101-
log(Level.Info, message, attributes, options)
108+
log(message, attributes, { ...options, level: Level.Info })
102109
}
103110

104111
export function trace(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
105-
log(Level.Trace, message, attributes, options)
112+
log(message, attributes, { ...options, level: Level.Trace })
106113
}
107114

108115
export function error(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
109-
log(Level.Error, message, attributes, options)
116+
log(message, attributes, { ...options, level: Level.Error })
110117
}
111118

112119
export function fatal(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
113-
log(Level.Fatal, message, attributes, options)
120+
log(message, attributes, { ...options, level: Level.Fatal })
114121
}
115122

116123
export function notice(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
117-
log(Level.Notice, message, attributes, options)
124+
log(message, attributes, { ...options, level: Level.Notice })
118125
}
119126

120127
export function warning(message: string, attributes: Record<string, unknown> = {}, options: LogOptions = {}) {
121-
log(Level.Warning, message, attributes, options)
128+
log(message, attributes, { ...options, level: Level.Warning })
122129
}
123130

124131
export function reportError(message: string, error: Error, extraAttributes: Record<string, unknown> = {}) {
125-
const span = startSpan(Level.Error, message, {
132+
const span = startSpan(message, {
126133
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
127134
[ATTR_EXCEPTION_MESSAGE]: error.message ?? 'error',
128135
[ATTR_EXCEPTION_STACKTRACE]: error.stack,

packages/logfire-cf-workers/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"postpack": "rm LICENSE"
5050
},
5151
"dependencies": {
52+
"@pydantic/logfire-api": "*",
5253
"@microlabs/otel-cf-workers": "^1.0.0-rc.49"
5354
},
5455
"devDependencies": {

packages/logfire-cf-workers/src/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'
2+
13
import { KVNamespace } from '@cloudflare/workers-types'
24
import { instrument as microlabsInstrument } from '@microlabs/otel-cf-workers'
3-
import { ReadableSpan } from '@opentelemetry/sdk-trace-base'
5+
import { AttributeScrubber, LogfireAttributeScrubber, serializeAttributes } from '@pydantic/logfire-api'
46

57
export interface CloudflareConfigOptions {
68
baseUrl?: string
@@ -22,6 +24,7 @@ export interface LogfireCloudflareConfigOptions {
2224
const DEFAULT_LOGFIRE_BASE_URL = 'https://logfire-api.pydantic.dev/'
2325

2426
function getConfig(config: LogfireCloudflareConfigOptions) {
27+
const scrubber = new LogfireAttributeScrubber()
2528
return (env: Env) => {
2629
let { LOGFIRE_BASE_URL: baseUrl = DEFAULT_LOGFIRE_BASE_URL, LOGFIRE_TOKEN: token } = env
2730

@@ -34,7 +37,7 @@ function getConfig(config: LogfireCloudflareConfigOptions) {
3437
headers: { Authorization: token },
3538
url: `${baseUrl}v1/traces`,
3639
},
37-
postProcessor: filterEmptyAttributes,
40+
postProcessor: (spans: ReadableSpan[]) => postProcessAttributes(spans, scrubber),
3841
service: {
3942
name: config.serviceName ?? 'cloudflare-worker',
4043
namespace: config.serviceNamespace ?? '',
@@ -58,7 +61,7 @@ function instrumentDO<T>(doClass: T, config: LogfireCloudflareConfigOptions): T
5861
}
5962
*/
6063

61-
function filterEmptyAttributes(spans: ReadableSpan[]) {
64+
function postProcessAttributes(spans: ReadableSpan[], scrubber: AttributeScrubber) {
6265
for (const span of spans) {
6366
for (const attrKey of Object.keys(span.attributes)) {
6467
const attrVal = span.attributes[attrKey]
@@ -68,6 +71,7 @@ function filterEmptyAttributes(spans: ReadableSpan[]) {
6871
delete span.attributes[attrKey]
6972
}
7073
}
74+
Object.assign(span.attributes, serializeAttributes(span.attributes, scrubber))
7175
}
7276
return spans
7377
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import defineConfig from '@pydantic/logfire-tooling-config/vite-config'
22
import { resolve } from 'node:path'
33

4-
export default defineConfig(resolve(__dirname, 'src/index.ts'), ['@microlabs/otel-cf-workers'])
4+
export default defineConfig(resolve(__dirname, 'src/index.ts'), ['@microlabs/otel-cf-workers', '@pydantic/logfire-api'])

0 commit comments

Comments
 (0)