Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3002ca9
feat: add `@opentelemetry/instrumentation-console` package for captur…
drdreo Dec 17, 2025
e92f1f3
chore: format
drdreo Dec 17, 2025
eab5e16
chore: remove open questions
drdreo Dec 17, 2025
5ce4f9a
chore: trigger CLA verification
drdreo Dec 17, 2025
43402e8
chore: trigger CLA verification
drdreo Dec 17, 2025
1b992d6
Update packages/instrumentation-console/package.json
drdreo Dec 18, 2025
cf2687d
chore: clean up imports and fix linting
drdreo Jan 2, 2026
5e9f1f2
Merge branch 'open-telemetry:main' into ot-console-instrumentation
drdreo Jan 6, 2026
e0c7941
chore: update linting from main
drdreo Jan 6, 2026
3dede67
refactor: PR feedback
drdreo Jan 7, 2026
9bbc0e7
chore: add instrumentation test app
drdreo Jan 7, 2026
f8a6bd7
Update packages/instrumentation-console/examples/package.json
drdreo Jan 9, 2026
04b8c00
Merge branch 'open-telemetry:main' into ot-console-instrumentation
drdreo Jan 15, 2026
caf96de
refactor: log context improvements
drdreo Jan 15, 2026
0c7b2e5
test: remove log spam in tests
drdreo Jan 15, 2026
d455a1d
refactor: remove trace parent context
drdreo Jan 22, 2026
5e9cb98
chore: update readme
drdreo Jan 25, 2026
20c0861
Merge branch 'main' into ot-console-instrumentation
martinkuba Jan 28, 2026
636d32a
Merge remote-tracking branch 'upstream/main' into ot-console-instrume…
drdreo Apr 13, 2026
331e74b
chore: move console instrumentation to new folder structure
drdreo Apr 13, 2026
4f81b2a
Merge remote-tracking branch 'upstream/main' into ot-console-instrume…
drdreo Apr 25, 2026
d261cf0
feat: make log methods dynamically configurable
drdreo Apr 25, 2026
35d05c7
Merge branch 'main' into ot-console-instrumentation
david-luna Apr 27, 2026
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
46 changes: 46 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

114 changes: 114 additions & 0 deletions packages/instrumentation-console/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# OpenTelemetry Console Instrumentation for Web

[![NPM Published Version][npm-img]][npm-url]
[![Apache License][license-image]][license-image]

This module provides automatic instrumentation for *console* methods (log, warn, error, info, debug) for Web applications, emitting them as OpenTelemetry logs which may be collected using the [`@opentelemetry/sdk-logs`](https://www.npmjs.com/package/@opentelemetry/sdk-logs) package.

Compatible with OpenTelemetry JS API and SDK `1.0+`.

## Installation

```bash
npm install @opentelemetry/instrumentation-console
```

## Usage

### Initialize

```typescript
import { logs } from '@opentelemetry/api-logs';
import { LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { ConsoleInstrumentation } from '@opentelemetry/instrumentation-console';
import { registerInstrumentations } from '@opentelemetry/instrumentation';

const logProvider = new LoggerProvider({
processors: [
new SimpleLogRecordProcessor(new OTLPLogExporter({
url: 'http://localhost:8000/v1/logs',
})),
],
});
logs.setGlobalLoggerProvider(logProvider);

registerInstrumentations({
instrumentations: [
new ConsoleInstrumentation(),
],
});

// Now all console calls will be captured as OpenTelemetry logs
console.log('Hello, World!');
console.error('Something went wrong!');
```

> **Warning:** Do not use this instrumentation with the `ConsoleSpanExporter` or `ConsoleLogRecordExporter`. This creates an infinite loop where console logs from the exporter itself are captured as new logs, creating more console output. Use exporters that send data over the network, such as `OTLPLogExporter`, `OTLPTraceExporter`, or other non-console exporters. See [OpenTelemetry Browser Exporters](https://opentelemetry.io/docs/languages/js/getting-started/browser/#creating-an-exporter) for available options.
Comment thread
drdreo marked this conversation as resolved.
Outdated

## Configuration

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `logMethods` | `ConsoleMethod[]` | `['log', 'warn', 'error', 'info', 'debug']` | Console methods to instrument |
| `messageSerializer` | `(args: unknown[]) => string` | See below | Custom serializer for console arguments |

### logMethods

Configure which console methods to instrument:

```typescript
new ConsoleInstrumentation({
logMethods: ['error', 'warn'], // Only capture errors and warnings
});
```

### messageSerializer

Provide a custom serializer for console arguments:

```typescript
new ConsoleInstrumentation({
messageSerializer: (args) => args.map(arg => String(arg)).join(' | '),
});
```

The default serializer joins arguments as strings, with objects serialized via `JSON.stringify`. Circular references are handled gracefully by falling back to `String(arg)`.

## Severity Mapping

Console methods are mapped to OpenTelemetry severity levels:

| Console Method | SeverityNumber | SeverityText |
|----------------|----------------|--------------|
| `debug` | DEBUG (5) | 'debug' |
| `log` | INFO (9) | 'log' |
| `info` | INFO (9) | 'info' |
| `warn` | WARN (13) | 'warn' |
| `error` | ERROR (17) | 'error' |

## Semantic Conventions

This package emits logs with the following attributes:

| Attribute | Description |
|-----------|-------------|
| `browser.console.method` | The console method that was called (e.g., 'log', 'error') |

Event name: `browser.console`

## Useful links

- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
- For more about OpenTelemetry Browser: <https://github.com/open-telemetry/opentelemetry-browser>
- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]

## License

Apache 2.0 - See [LICENSE][license-url] for more information.

[discussions-url]: https://github.com/open-telemetry/opentelemetry-browser/discussions/landing
[license-url]: https://github.com/open-telemetry/opentelemetry-browser/blob/main/LICENSE
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
[npm-url]: https://www.npmjs.com/package/@opentelemetry/instrumentation-console
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Finstrumentation-console.svg
12 changes: 12 additions & 0 deletions packages/instrumentation-console/examples/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenTelemetry Browser Console Test App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
11 changes: 11 additions & 0 deletions packages/instrumentation-console/examples/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "ot-test-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
73 changes: 73 additions & 0 deletions packages/instrumentation-console/examples/src/console.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { logs } from '@opentelemetry/api-logs';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { resourceFromAttributes } from '@opentelemetry/resources';
import {
ConsoleLogRecordExporter,
LoggerProvider,
SimpleLogRecordProcessor,
} from '@opentelemetry/sdk-logs';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
import { ConsoleInstrumentation } from '../../src/index.ts';

export function setupConsoleDemo(element: HTMLDivElement) {
const resourceSettings = resourceFromAttributes({
[ATTR_SERVICE_NAME]: 'OpenTelemetry Browser Test',
});

const loggerProvider = new LoggerProvider({
resource: resourceSettings,
processors: [new SimpleLogRecordProcessor(new ConsoleLogRecordExporter())],
});
logs.setGlobalLoggerProvider(loggerProvider);

registerInstrumentations({
loggerProvider,
instrumentations: [new ConsoleInstrumentation()],
});

element.innerHTML = `
<div class="button-group">
<button id="btn-log">console.log</button>
<button id="btn-info">console.info</button>
<button id="btn-warn">console.warn</button>
<button id="btn-error">console.error</button>
<button id="btn-debug">console.debug</button>
</div>
<p class="hint">Open <code>DevTools Console</code> to see the output and traces</p>
`;

const btnLog = element.querySelector<HTMLButtonElement>('#btn-log');
if (btnLog) {
btnLog.addEventListener('click', () => {
console.log('Test log message', { foo: 'bar' });
});
}

const btnInfo = element.querySelector<HTMLButtonElement>('#btn-info');
if (btnInfo) {
btnInfo.addEventListener('click', () => {
console.info('Test info message');
});
}

const btnWarn = element.querySelector<HTMLButtonElement>('#btn-warn');
if (btnWarn) {
btnWarn.addEventListener('click', () => {
console.warn('Test warning message');
});
}

const btnError = element.querySelector<HTMLButtonElement>('#btn-error');
if (btnError) {
btnError.addEventListener('click', () => {
console.error('Test error message');
});
}

const btnDebug = element.querySelector<HTMLButtonElement>('#btn-debug');
if (btnDebug) {
btnDebug.addEventListener('click', () => {
console.debug('Test debug message');
});
}
}
18 changes: 18 additions & 0 deletions packages/instrumentation-console/examples/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import './styles.css';

import { setupConsoleDemo } from './console.ts';

const appElement = document.querySelector<HTMLDivElement>('#app');
if (appElement) {
appElement.innerHTML = `
<div>
<h1>Console Instrumentation Demo</h1>
<div id="console-demo"></div>
</div>
`;

const demosElement = document.querySelector<HTMLDivElement>('#console-demo');
if (demosElement) {
setupConsoleDemo(demosElement);
}
}
Loading