Logger
@granit/logger provides a structured logging system for browser applications with
configurable severity levels, named prefixes, child loggers, and a pluggable transport
architecture. @granit/logger-otlp adds an OTLP HTTP transport that sends logs to an
OpenTelemetry collector (Grafana Alloy, Aspire Dashboard) with trace correlation —
pairing with Granit.Observability on the .NET backend.
Package structure
Section titled “Package structure”Directory@granit/logger/ Logger factory, console transport, transport interface
- @granit/logger-otlp OTLP HTTP transport for OpenTelemetry collectors
| Package | Role | Depends on |
|---|---|---|
@granit/logger | createLogger(), createConsoleTransport(), LogLevel | — (no peer deps) |
@granit/logger-otlp | createOtlpTransport() for OTLP HTTP log export | @granit/logger |
import { createLogger } from '@granit/logger';
const logger = createLogger('MyApp');
logger.info('Application started');logger.error('Something failed', new Error('connection refused'));No configuration needed. Defaults to createConsoleTransport() with colored DevTools output.
import { createLogger, createConsoleTransport } from '@granit/logger';import { createOtlpTransport } from '@granit/logger-otlp';import { getTraceContext } from '@granit/tracing';
const logger = createLogger('MyApp', { level: 'INFO', transports: [ createConsoleTransport(), createOtlpTransport({ endpoint: '/v1/logs', serviceName: 'guava-front', serviceVersion: '1.0.0', environment: 'production', getTraceContext, // log-to-trace correlation }), ],});TypeScript SDK
Section titled “TypeScript SDK”createLogger(prefix, options?)
Section titled “createLogger(prefix, options?)”Creates a logger instance with a named prefix and configurable transports.
interface LoggerOptions { level?: LogLevelName; // default: auto-detected from Vite environment transports?: LogTransport[]; // default: [createConsoleTransport()]}
function createLogger(prefix: string, options?: LoggerOptions): Logger;Level auto-detection: defaults to 'DEBUG' in Vite dev mode (import.meta.env.DEV),
'WARN' in production builds.
Logger interface
Section titled “Logger interface”interface Logger { debug(message: string, context?: LogContext): void; info(message: string, context?: LogContext): void; warn(message: string, context?: LogContext): void; error(message: string, error?: unknown, context?: LogContext): void; child(subPrefix: string): Logger;}
type LogContext = Record<string, unknown>;Child loggers inherit the parent’s level and transports. Prefixes are concatenated:
const auth = createLogger('Auth');const token = auth.child('Token');token.info('Refreshed'); // "[Auth] [Token] Refreshed"Log levels
Section titled “Log levels”const LogLevel = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3,} as const;
type LogLevelName = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';type LogLevelValue = 0 | 1 | 2 | 3;| Level | Console method | DevTools badge color |
|---|---|---|
DEBUG | console.log | Grey #71717a |
INFO | console.info | Blue #0ea5e9 |
WARN | console.warn | Amber #f59e0b |
ERROR | console.error | Red #ef4444 |
Transport interface
Section titled “Transport interface”interface LogTransport { send(entry: LogEntry): void; flush?(): Promise<void>;}
interface LogEntry { timestamp: number; // Unix ms (Date.now()) level: LogLevelName; prefix: string; message: string; error?: unknown; context?: LogContext;}Any transport with a flush() method is automatically registered for a shared
beforeunload event listener to ensure logs are delivered before the page closes.
createConsoleTransport()
Section titled “createConsoleTransport()”Built-in transport that outputs colored, prefixed messages to the browser DevTools console.
function createConsoleTransport(): LogTransport;OTLP transport
Section titled “OTLP transport”@granit/logger-otlp sends logs as OTLP JSON to an OpenTelemetry-compatible collector.
Logs are batched and flushed periodically for efficiency.
createOtlpTransport(options)
Section titled “createOtlpTransport(options)”interface OtlpTransportOptions { endpoint: string; // e.g. '/v1/logs' or full URL serviceName: string; // e.g. 'guava-front' serviceVersion?: string; environment?: string; // e.g. 'production' headers?: Record<string, string>; // additional HTTP headers batchSize?: number; // auto-flush threshold, default: 10 flushInterval?: number; // ms between flushes, default: 5_000 getTraceContext?: () => TraceContext | undefined; // log-to-trace correlation}
interface TraceContext { traceId: string; spanId: string;}
function createOtlpTransport(options: OtlpTransportOptions): LogTransport;OTLP mapping:
- Log levels map to OTLP severity numbers:
DEBUG=5,INFO=9,WARN=13,ERROR=17 - Resource attributes:
service.name,service.version,deployment.environment - Log attributes:
logger.prefix, context key-values, andexception.*forErrorobjects - Uses
fetchwithkeepalive: truefor reliable delivery on page unload - Self-disables on first network or HTTP error to avoid log spam
Vite proxy for development
Section titled “Vite proxy for development”Route OTLP requests to the Aspire Dashboard (or local collector) via Vite’s dev server proxy:
export default defineConfig({ server: { proxy: { '/v1/logs': 'http://localhost:18889', }, },});Log-to-trace correlation
Section titled “Log-to-trace correlation”Pass getTraceContext from @granit/tracing to correlate logs with distributed traces
in Grafana (Loki → Tempo):
import { getTraceContext } from '@granit/tracing';
createOtlpTransport({ endpoint: '/v1/logs', serviceName: 'guava-front', getTraceContext,});Each log entry includes traceId and spanId from the active OpenTelemetry span,
enabling direct navigation from a log line to its trace in Grafana Tempo.
Public API summary
Section titled “Public API summary”| Category | Key exports | Package |
|---|---|---|
| Factory | createLogger() | @granit/logger |
| Transport | createConsoleTransport(), LogTransport | @granit/logger |
| OTLP | createOtlpTransport(), OtlpTransportOptions, TraceContext | @granit/logger-otlp |
| Types | Logger, LogEntry, LogContext, LoggerOptions | @granit/logger |
| Constants | LogLevel, LogLevelName, LogLevelValue | @granit/logger |
See also
Section titled “See also”- Granit.Observability module — .NET Serilog + OpenTelemetry
- Tracing — OpenTelemetry browser tracing,
getTraceContext()for correlation - Error boundary — uses
@granit/loggerfor error reporting