diff --git a/docs/integrations/javascript/browser.md b/docs/integrations/javascript/browser.md index d8151c989..98e09f08f 100644 --- a/docs/integrations/javascript/browser.md +++ b/docs/integrations/javascript/browser.md @@ -7,8 +7,12 @@ integration: logfire The `@pydantic/logfire-browser` NPM package wraps [OpenTelemetry browser tracing](https://opentelemetry.io/docs/languages/js/getting-started/browser/) with sensible defaults and provides a simple API for creating spans and reporting exceptions. -!!! info - Logfire does not directly expose an endpoint suitable for sending traces from the browser, as this would make your write token publicly accessible. To send traces from the browser, you must create a proxy in your app that **forwards requests from your browser instrumentation to Logfire** while adding the `Authorization` header. Check the [Next.js proxy example implementation](https://github.com/pydantic/logfire-js/blob/main/examples/nextjs-client-side-instrumentation/proxy.ts) for more details. +!!! info "Securely Sending Traces" + Logfire does not directly expose an endpoint suitable for sending traces from the browser, as this would make your write token publicly accessible. + + To safely send traces, you must route them through a backend proxy that attaches the `Authorization` header server-side. + - **Python:** Use the built-in `logfire_proxy` handler for [FastAPI](../web-frameworks/fastapi.md#proxying-browser-telemetry) or [Starlette](../web-frameworks/starlette.md#proxying-browser-telemetry). + - **Next.js:** Check out the [Next.js proxy example implementation](https://github.com/pydantic/logfire-js/blob/main/examples/nextjs-client-side-instrumentation/proxy.ts). ## Simple Usage @@ -16,9 +20,10 @@ The `@pydantic/logfire-browser` NPM package wraps [OpenTelemetry browser tracing import { getWebAutoInstrumentations } from "@opentelemetry/auto-instrumentations-web"; import * as logfire from '@pydantic/logfire-browser'; -// Set the path to your traces proxy endpoint - assuming it's hosted at `/client-traces`, same domain. +// Set the path to your backend proxy endpoint +// For example, if using the Python `logfire_proxy` handler hosted on the same domain: const url = new URL(window.location.href); -url.pathname = "/client-traces"; +url.pathname = "/logfire-proxy/v1/traces"; logfire.configure({ traceUrl: url.toString(), @@ -26,7 +31,7 @@ logfire.configure({ serviceVersion: '0.1.0', // The instrumentations to use // https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-web - for more options and configuration - instrumentations: [ + instrumentations:[ getWebAutoInstrumentations() ], // This outputs details about the generated spans in the browser console, use only in development and for troubleshooting. diff --git a/docs/integrations/web-frameworks/fastapi.md b/docs/integrations/web-frameworks/fastapi.md index b8fa86e2e..9368ac1dd 100644 --- a/docs/integrations/web-frameworks/fastapi.md +++ b/docs/integrations/web-frameworks/fastapi.md @@ -109,6 +109,52 @@ The main request span will still have the attributes described above, but it wil This is mostly redundant now and is mainly provided for backwards compatibility. It can also be useful for grouping together child logs and spans produced by the request. + +## Proxying Browser Telemetry + +If you have a frontend application (e.g., React, Vue, or Vanilla JS) that sends telemetry from the browser, you should **never** expose your Logfire Write Token in the frontend code. + +Instead, you can use experimental proxy handler to securely forward OTLP telemetry from the browser through your FastAPI backend to Logfire. + +```py title="main.py" skip-run="true" skip-reason="server-start" +from fastapi import FastAPI, Request + +import logfire +from logfire.experimental.forwarding import logfire_proxy + +logfire.configure() +app = FastAPI() + + +# Mount the proxy handler +# Note: {path:path} is strictly required to capture the OTLP route (e.g., /v1/traces) +@app.post('/logfire-proxy/{path:path}') +async def proxy_browser_telemetry(request: Request): + return await logfire_proxy(request) +``` + +By default, this endpoint is unauthenticated and accepts payloads up to 50MB. In production, you should protect it using FastAPI dependencies to prevent abuse: + +```py skip-run="true" skip-reason="server-start" +from fastapi import Depends, FastAPI, Request + +import logfire +from logfire.experimental.forwarding import logfire_proxy + +logfire.configure() +app = FastAPI() + + +async def verify_user_session(): + # Implement your authentication/rate-limiting logic here + pass + + +@app.post('/logfire-proxy/{path:path}', dependencies=[Depends(verify_user_session)]) +async def proxy_browser_telemetry_secure(request: Request): + return await logfire_proxy(request) +``` + [fastapi]: https://fastapi.tiangolo.com/ [opentelemetry-asgi]: https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/asgi/asgi.html [opentelemetry-fastapi]: https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/fastapi/fastapi.html diff --git a/docs/integrations/web-frameworks/starlette.md b/docs/integrations/web-frameworks/starlette.md index 2bdd75598..b481068f2 100644 --- a/docs/integrations/web-frameworks/starlette.md +++ b/docs/integrations/web-frameworks/starlette.md @@ -55,6 +55,33 @@ The keyword arguments of `logfire.instrument_starlette()` are passed to the `Sta `StarletteInstrumentor` actually wraps the ASGI middleware and adds some additional information related to the routes. + +## Proxying Browser Telemetry + +If you have a frontend application sending telemetry from the browser, you should **never** expose your Logfire Write Token in the frontend code. + +Instead, you can use experimental proxy handler to securely forward OTLP telemetry from the browser through your Starlette backend to Logfire. + +```py title="main.py" skip-run="true" skip-reason="server-start" +from starlette.applications import Starlette +from starlette.routing import Route + +import logfire +from logfire.experimental.forwarding import logfire_proxy + +logfire.configure() + +app = Starlette( + routes=[ + # Note: {path:path} is strictly required to capture the OTLP route (e.g., /v1/traces) + Route('/logfire-proxy/{path:path}', logfire_proxy, methods=['POST']) + ] +) +``` + +!!! warning "Security Note" + By default, this endpoint is unauthenticated. In production, ensure you wrap this route with appropriate authentication middleware or rate-limiting to prevent unauthorized clients from sending arbitrary telemetry to your Logfire project. + [starlette]: https://www.starlette.io/ [opentelemetry-asgi]: https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/asgi/asgi.html [opentelemetry-starlette]: https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/starlette/starlette.html