Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/fix-default-export-vite-dts-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@pydantic/logfire-api': minor
'@pydantic/logfire-browser': minor
'@pydantic/logfire-cf-workers': minor
'logfire': minor
---

Add default export to packages. Using the default import is equivalent to the star import.
13 changes: 13 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"permissions": {
"allow": [
"Bash(cat:*)",
"WebSearch",
"Bash(npm run build)",
"Bash(npm run build:*)",
"Bash(npx changeset:*)"
],
"deny": [],
"ask": []
}
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ node_modules
packages/*/*.tgz
.turbo
.env
CLAUDE.md
scratch/
185 changes: 185 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

This is a monorepo for the **Pydantic Logfire JavaScript SDK** - an observability platform built on OpenTelemetry. The repository contains multiple packages for different JavaScript runtimes (Node.js, browsers, Cloudflare Workers, etc.) and usage examples.

## Repository Structure

This is an **npm workspace monorepo** managed with **Turborepo**:

- `packages/logfire` - Main Node.js SDK with automatic OpenTelemetry instrumentation
- `packages/logfire-api` - Core API package that can be used standalone for manual tracing (no auto-instrumentation)
- `packages/logfire-cf-workers` - Cloudflare Workers integration
- `packages/logfire-browser` - Browser/web SDK
- `packages/tooling-config` - Shared build and linting configuration
- `examples/` - Working examples for various platforms (Express, Next.js, Deno, Cloudflare Workers, etc.)

## Core Architecture

### Package Relationships

- `logfire-api` is the base package that provides the core tracing API (`span`, `info`, `debug`, `error`, etc.) - it wraps OpenTelemetry's trace API with convenience methods
- `logfire` (Node.js SDK) depends on `logfire-api` and adds automatic instrumentation via `@opentelemetry/auto-instrumentations-node`
- `logfire-cf-workers` depends on `logfire-api` and adds Cloudflare Workers-specific instrumentation
- `logfire-browser` depends on `logfire-api` and adds browser-specific instrumentation

### Key Concepts

**Trace API** (`logfire-api`):

- Provides convenience wrappers around OpenTelemetry spans with log levels (trace, debug, info, notice, warn, error, fatal)
- Uses message template formatting with attribute extraction (see `formatter.ts`)
- Uses ULID for trace ID generation (see `ULIDGenerator.ts`)
- Supports attribute scrubbing for sensitive data (see `AttributeScrubber.ts`)

**Configuration** (`logfire` package):

- `configure()` function in `logfireConfig.ts` handles SDK initialization
- Configuration can be provided programmatically or via environment variables:
- `LOGFIRE_TOKEN` - Authentication token
- `LOGFIRE_SERVICE_NAME` - Service name
- `LOGFIRE_SERVICE_VERSION` - Service version
- `LOGFIRE_ENVIRONMENT` - Deployment environment
- `LOGFIRE_CONSOLE` - Enable console output
- `LOGFIRE_SEND_TO_LOGFIRE` - Toggle sending to Logfire backend
- `LOGFIRE_DISTRIBUTED_TRACING` - Enable/disable trace context propagation

**Span Creation**:

- `startSpan()` - Creates a span without setting it on context (manual mode)
- `span()` - Creates a span, executes a callback, and auto-ends the span (recommended)
- `info()`, `debug()`, `error()`, etc. - Convenience methods that create log-type spans
- All spans use message templates with attribute extraction (e.g., `"User {user_id} logged in"`)

## Common Commands

### Development Setup

```bash
npm install
```

### Building

```bash
# Build all packages
npm run build

# Build in watch mode (for development)
npm run dev
```

### Testing

```bash
# Run all tests
npm run test

# Run tests for a specific package
cd packages/logfire && npm test
```

### Linting and Type Checking

```bash
# Run both typecheck and lint across all packages
npm run ci

# Just linting
turbo lint

# Just type checking
turbo typecheck
```

### Working with Examples

Start an example to test changes:

```bash
# Navigate to an example
cd examples/node # or express, nextjs, cf-worker, etc.

# Install dependencies (if needed)
npm install

# Run the example (check the example's package.json for scripts)
npm start # or npm run dev
```

### Changesets (Version Management)

This project uses Changesets for version management:

```bash
# Add a changeset when making changes
npm run changeset-add

# Publish packages (maintainers only)
npm run release
```

### Running a Single Test

```bash
# Navigate to the package
cd packages/logfire-api

# Run vitest with a filter
npm test -- -t "test name pattern"
```

## Development Workflow

1. Make changes in `packages/` source code
2. Run `npm run build` to rebuild packages (or `npm run dev` for watch mode)
3. Test changes using examples in `examples/` directory
4. Run `npm run ci` to ensure linting and type checking pass
5. Add a changeset if the changes warrant a version bump: `npm run changeset-add`

## Important Implementation Details

### Message Template Formatting

The `logfireFormatWithExtras()` function in `formatter.ts` extracts attributes from message templates. For example:

- `"User {user_id} logged in"` with `{ user_id: 123 }` becomes formatted message `"User 123 logged in"`
- Extracted attributes are stored with special keys and used by the Logfire backend

### Attribute Scrubbing

Sensitive data scrubbing is handled in `AttributeScrubber.ts`. By default, it redacts common sensitive patterns (passwords, tokens, API keys, etc.) using regex patterns.

### Span Types

Spans have a `logfire.span_type` attribute:

- `"log"` - Point-in-time events (no child spans expected)
- `"span"` - Duration-based traces (can have child spans)

### ID Generation

The SDK uses ULID (Universally Unique Lexicographically Sortable Identifier) for trace IDs by default, which provides time-ordered IDs for better performance.

### Build System

- Uses Vite for building packages (see individual `vite.config.ts` files)
- Shared Vite config is in `packages/tooling-config/vite-config.ts`
- Outputs both ESM (`.js`) and CommonJS (`.cjs`) formats with corresponding TypeScript definitions

## Testing Notes

- Tests use Vitest
- Some packages have minimal tests (`--passWithNoTests` flag in package.json)
- Test files are located alongside source files with `.test.ts` extension

## Node Version

The project requires **Node.js 22** (see `engines` in root package.json).

## Package Manager

Uses **npm 10.9.2** (enforced via `packageManager` field).
21 changes: 21 additions & 0 deletions agent/prompts/add-default-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Default export addition

I need to add a default export to all packages in this monorepo. The default export object should be the same as the star import. For example, the following two codes are equivalent:

```ts
import * as logfire from 'logfire';
```

```ts
import logfire from 'logfire';
```

Implement this for every package in the monorepo. Do not touch the examples.

## Details

Explicitly construct the default export object using the current imports. This should happen in the index.ts files.

## Testing

Test this feature by rebuilding the packages and verifying the resulting bundles.
1 change: 0 additions & 1 deletion examples/cf-tail-worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
"test": "vitest",
"cf-typegen": "wrangler types"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"test": "turbo test",
"release": "turbo build && npx @changesets/cli publish",
"changeset-add": "npx @changesets/cli add",
"ci": "turbo typecheck lint"
"ci": "turbo typecheck lint test"
},
"keywords": [],
"author": "",
Expand Down
2 changes: 1 addition & 1 deletion packages/logfire-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"typecheck": "tsc",
"prepack": "cp ../../LICENSE .",
"postpack": "rm LICENSE",
"test": "vitest"
"test": "vitest run"
},
"devDependencies": {
"@opentelemetry/api": "^1.9.0",
Expand Down
14 changes: 11 additions & 3 deletions packages/logfire-api/src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { trace } from '@opentelemetry/api'
import { beforeEach, describe, expect, test, vi } from 'vitest'

import { ATTRIBUTES_LEVEL_KEY, ATTRIBUTES_MESSAGE_TEMPLATE_KEY, ATTRIBUTES_SPAN_TYPE_KEY, ATTRIBUTES_TAGS_KEY } from './constants'
import {
ATTRIBUTES_LEVEL_KEY,
ATTRIBUTES_MESSAGE_KEY,
ATTRIBUTES_MESSAGE_TEMPLATE_KEY,
ATTRIBUTES_SPAN_TYPE_KEY,
ATTRIBUTES_TAGS_KEY,
} from './constants'
import { info } from './index'

vi.mock('@opentelemetry/api', () => {
Expand Down Expand Up @@ -35,10 +41,11 @@ describe('info', () => {

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(tracer.startSpan).toBeCalledWith(
'aha 1',
'aha {i}',
{
attributes: {
[ATTRIBUTES_LEVEL_KEY]: 9,
[ATTRIBUTES_MESSAGE_KEY]: 'aha 1',
[ATTRIBUTES_MESSAGE_TEMPLATE_KEY]: 'aha {i}',
[ATTRIBUTES_SPAN_TYPE_KEY]: 'log',
[ATTRIBUTES_TAGS_KEY]: [],
Expand All @@ -55,10 +62,11 @@ describe('info', () => {

// eslint-disable-next-line @typescript-eslint/unbound-method
expect(tracer.startSpan).toBeCalledWith(
'aha 1',
'aha {i}',
{
attributes: {
[ATTRIBUTES_LEVEL_KEY]: 9,
[ATTRIBUTES_MESSAGE_KEY]: 'aha 1',
[ATTRIBUTES_MESSAGE_TEMPLATE_KEY]: 'aha {i}',
[ATTRIBUTES_SPAN_TYPE_KEY]: 'log',
[ATTRIBUTES_TAGS_KEY]: [],
Expand Down
37 changes: 27 additions & 10 deletions packages/logfire-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Span, SpanStatusCode, context as TheContextAPI, trace as TheTraceAPI } from '@opentelemetry/api'
import { ATTR_EXCEPTION_MESSAGE, ATTR_EXCEPTION_STACKTRACE } from '@opentelemetry/semantic-conventions'

import * as AttributeScrubbingExports from './AttributeScrubber'
import {
ATTRIBUTES_LEVEL_KEY,
ATTRIBUTES_MESSAGE_KEY,
Expand All @@ -10,22 +11,16 @@ import {
ATTRIBUTES_TAGS_KEY,
} from './constants'
import { logfireFormatWithExtras } from './formatter'
import { logfireApiConfig, ScrubbingOptions, serializeAttributes } from './logfireApiConfig'
import { logfireApiConfig, serializeAttributes } from './logfireApiConfig'
import * as logfireApiConfigExports from './logfireApiConfig'
import * as ULIDGeneratorExports from './ULIDGenerator'

export * from './AttributeScrubber'
export { configureLogfireApi, logfireApiConfig, resolveBaseUrl, resolveSendToLogfire } from './logfireApiConfig'
export type { ScrubbingOptions } from './logfireApiConfig'
export type { LogfireApiConfig, LogfireApiConfigOptions, ScrubbingOptions } from './logfireApiConfig'
export { serializeAttributes } from './serializeAttributes'
export * from './ULIDGenerator'

export interface LogfireApiConfigOptions {
otelScope?: string
/**
* Options for scrubbing sensitive data. Set to False to disable.
*/
scrubbing?: false | ScrubbingOptions
}

export const Level = {
Trace: 1 as const,
Debug: 5 as const,
Expand Down Expand Up @@ -211,3 +206,25 @@ export function reportError(message: string, error: Error, extraAttributes: Reco
span.setStatus({ code: SpanStatusCode.ERROR })
span.end()
}

const defaultExport = {
...AttributeScrubbingExports,
...ULIDGeneratorExports,
...logfireApiConfigExports,

serializeAttributes,
Level,
startSpan,
span,
log,
debug,
info,
trace,
error,
fatal,
notice,
warning,
reportError,
}

export default defaultExport
2 changes: 1 addition & 1 deletion packages/logfire-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"typecheck": "tsc",
"prepack": "cp ../../LICENSE .",
"postpack": "rm LICENSE",
"test": "vitest --passWithNoTests"
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
Expand Down
Loading