Skip to content

Commit 2771f37

Browse files
committed
Support dynamic headers in logfire-browser
1 parent f8903c9 commit 2771f37

File tree

13 files changed

+872
-117
lines changed

13 files changed

+872
-117
lines changed

.changeset/cold-turkeys-argue.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pydantic/logfire-browser": minor
3+
---
4+
5+
Support dynamic headers for the proxy URL

examples/browser/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

examples/browser/README.md

Whitespace-only changes.

examples/browser/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + TS</title>
8+
</head>
9+
<body>
10+
<div id="app">
11+
12+
<button onclick="console.log(1)">Click</button>
13+
</div>
14+
<script type="module" src="/src/main.ts"></script>
15+
</body>
16+
</html>

examples/browser/package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "browser",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc && vite build",
9+
"proxy": "tsx --env-file=.env src/proxy.ts",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@opentelemetry/auto-instrumentations-web": "^0.49.0",
14+
"cors": "^2.8.5",
15+
"express": "^4.21.2",
16+
"express-http-proxy": "^2.1.1",
17+
"http-proxy-middleware": "^2.0.6"
18+
},
19+
"devDependencies": {
20+
"@pydantic/logfire-api": "*",
21+
"@pydantic/logfire-browser": "*",
22+
"@types/cors": "^2.8.17",
23+
"@types/express": "^4.17.21",
24+
"tsx": "^4.7.0",
25+
"typescript": "~5.8.3",
26+
"vite": "^7.0.4"
27+
}
28+
}

examples/browser/src/main.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { getWebAutoInstrumentations } from "@opentelemetry/auto-instrumentations-web";
2+
import * as logfire from '@pydantic/logfire-browser';
3+
4+
5+
logfire.configure({
6+
traceUrl: 'http://localhost:8989/client-traces',
7+
serviceName: 'my-service',
8+
serviceVersion: '0.1.0',
9+
// The instrumentations to use
10+
// https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-web - for more options and configuration
11+
instrumentations: [
12+
getWebAutoInstrumentations({
13+
"@opentelemetry/instrumentation-document-load": { enabled: true },
14+
"@opentelemetry/instrumentation-user-interaction": {
15+
eventNames: ['click']
16+
},
17+
})
18+
],
19+
// This outputs details about the generated spans in the browser console, use only in development and for troubleshooting.
20+
diagLogLevel: logfire.DiagLogLevel.ALL,
21+
batchSpanProcessorConfig: {
22+
maxExportBatchSize: 10
23+
},
24+
})
25+
26+
27+
document.querySelector('button')?.addEventListener('click', () => {
28+
fetch('https://jsonplaceholder.typicode.com/posts/1')
29+
})

examples/browser/src/proxy.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import express from 'express';
2+
import cors from 'cors';
3+
4+
const app = express();
5+
const PORT = 8989;
6+
7+
// Enable CORS - handle origins dynamically to avoid wildcard issues with credentials
8+
app.use(cors({
9+
origin: '*',
10+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
11+
credentials: true
12+
}));
13+
14+
// Parse JSON bodies
15+
app.use(express.json());
16+
17+
const logfireUrl = process.env.LOGFIRE_URL || 'http://localhost:4318/v1/traces';
18+
const token = process.env.LOGFIRE_TOKEN || ''
19+
20+
21+
// Single endpoint: POST /client-traces
22+
app.post('/client-traces', async (req, res) => {
23+
const response = await fetch(logfireUrl, {
24+
method: 'POST',
25+
headers: {
26+
'Content-Type': 'application/json',
27+
'Authorization': token
28+
},
29+
body: JSON.stringify(req.body),
30+
})
31+
res.status(response.status).send(response.body)
32+
});
33+
34+
// Start the server
35+
app.listen(PORT, () => {
36+
console.log(`Server running on port ${PORT}, proxying to ${logfireUrl}`);
37+
});
38+
39+
export default app;
40+

examples/browser/src/vite-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />

examples/browser/tsconfig.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2022",
4+
"useDefineForClassFields": true,
5+
"module": "ESNext",
6+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
7+
"skipLibCheck": true,
8+
9+
/* Bundler mode */
10+
"moduleResolution": "bundler",
11+
"allowImportingTsExtensions": true,
12+
"verbatimModuleSyntax": true,
13+
"moduleDetection": "force",
14+
"noEmit": true,
15+
16+
/* Linting */
17+
"strict": true,
18+
"noUnusedLocals": true,
19+
"noUnusedParameters": true,
20+
"erasableSyntaxOnly": true,
21+
"noFallthroughCasesInSwitch": true,
22+
"noUncheckedSideEffectImports": true
23+
},
24+
"include": ["src"]
25+
}

0 commit comments

Comments
 (0)