Sending Logs from your frontend application
This documentation provides steps for sending logs from your frontend application to SigNoz.
SigNoz natively supports OpenTelemetry for collecting logs, so you can lift-and-shift existing log libraries or build new pipelines, all with the same unified model as your traces and metrics.
Logs can be collected on the client side at meaningful points to capture various events, state changes, errors and warnings.
Prerequisites
- SigNoz Cloud or self-hosted account
- A web application from where you want to send logs
Setup
Step 1: Setup OTel Collector
Install the OpenTelemetry Collector binary using these instructions. The Collector acts as an agent that receives, processes, and exports telemetry data. It is required to collect data from your application, including logs.
You would also need to update the collector config to whitelist the frontend domain. This is required to allow Cross-Origin Resource Sharing (CORS) requests from your frontend application to the OpenTelemetry collector.
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- <<YOUR_FRONTEND_URL>>
allowed_headers: ['*']
Step 2: Install dependencies
Install the following dependencies.
npm i \
@opentelemetry/resources \
@opentelemetry/sdk-logs \
@opentelemetry/exporter-logs-otlp-http \
@opentelemetry/api-logs
Read more about the dependencies
@opentelemetry/resources
: Provides resource attributes that identify your service (like service name, version, etc.). This helps distinguish logs from different services in your SigNoz dashboard.@opentelemetry/sdk-logs
: Contains the core logging SDK implementation includingLoggerProvider
andSimpleLogRecordProcessor
. This is the foundation for creating and processing log records in your application.@opentelemetry/exporter-logs-otlp-http
: Implements the OTLP (OpenTelemetry Protocol) HTTP exporter that sends your logs to the SigNoz collector. This handles the actual transmission of log data over HTTP.@opentelemetry/api-logs
: Provides the logging API interface (logs
object) that your application code uses to create log records. This is the main API you'll interact with when adding logging statements to your code.
Step 3: Create an instrumentation file
The instrumentation file is required to setup the LoggerProvider
which is used to create custom logs within your application and export them to your collector. Inside your src
directory, create a file named instrument.js
(or instrument.ts
for TypeScript):
import {
LoggerProvider,
SimpleLogRecordProcessor,
} from '@opentelemetry/sdk-logs';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { logs } from '@opentelemetry/api-logs';
import { resourceFromAttributes } from '@opentelemetry/resources';
const loggerProvider = new LoggerProvider({
resource: resourceFromAttributes({
'service.name': '<<SERVICE_NAME>>',
}),
processors: [
new OTLPLogExporter({
url: `https://ingest.<<INGESTION_REGION>>.signoz.cloud:443/v1/logs`,
headers: {
'signoz-ingestion-key': <<INGESTION_KEY>>,
},
})
],
});
logs.setGlobalLoggerProvider(loggerProvider);
- Set the
<<INGESTION_REGION>>
to match your SigNoz Cloud region - Replace
<<INGESTION_KEY>>
with your SigNoz ingestion key <<SERVICE_NAME>>
is the name of your service
Step 4: Importing the instrumentation file
Import the instrumentation file at the top level of your application. This ensures that the OpenTelemetry instrumentation is initialized before any other code runs, allowing it to capture logs from the very beginning of your application's execution.
import './instrument';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>
);
Step 5: Create utility functions for Logging
The utils
file will contain our utility functions for recording various kinds of logs (info
, warning
, error
).
import {
logs,
SeverityNumber,
type AnyValueMap,
} from '@opentelemetry/api-logs';
const logger = logs.getLogger('frontend-logger');
export function logInfo(body: string, attrs: AnyValueMap = {}) {
logger.emit({
body,
severityNumber: SeverityNumber.INFO,
severityText: 'INFO',
attributes: attrs,
});
}
export function logWarn(body: string, attrs: AnyValueMap = {}) {
logger.emit({
body,
severityNumber: SeverityNumber.WARN,
severityText: 'WARN',
attributes: attrs,
});
}
export function logError(body: string, attrs: AnyValueMap = {}) {
logger.emit({
body,
severityNumber: SeverityNumber.ERROR,
severityText: 'ERROR',
attributes: attrs,
});
}
Step 6: Setting up Logs within your Application
Add logs at meaningful points in your application.
function onNextClick() {
try {
const response = await fetch('/api/data');
const data = await response.json();
logInfo('Next button clicked!', { data });
return data;
} catch (error) {
logError('Failed to fetch data', { error: error.message });
}
}
Step 7: Viewing Captured Logs in SigNoz
The captured logs can then be viewed in the Logs Explorer.

Attaching additional identifiers to your Logs
You can enrich logs with additional metadata like browser type, user ID etc. to enable real user monitoring (RUM)-like insights.
To do so, you need to write a custom implementation on top of LogRecordProcessor
which will intercept all your exported logs and attach additional attributes to them.
import type { LogRecordProcessor, SdkLogRecord } from '@opentelemetry/sdk-logs';
import { UAParser } from 'ua-parser-js';
function getBrowserInfo() {
// You can add your custom browser tracking logic here as well.
// This example uses the ua-parser-js package.
const parser = new UAParser();
const result = parser.getResult();
return {
browserName: result.browser.name,
browserVersion: result.browser.version,
userAgent: result.ua,
};
}
function getUserId() {
// You can add your custom user ID tracking logic here as well.
// This example uses localStorage.
const userId = localStorage.getItem('userId');
return {
userId,
};
}
function getAdditionalAttributes() {
return {
...getBrowserInfo(),
...getUserId(),
};
}
export class CustomAttributesProcessor implements LogRecordProcessor {
onEmit(logRecord: SdkLogRecord) {
const additionalAttrs = getAdditionalAttributes();
logRecord.setAttributes(additionalAttrs);
}
shutdown(): Promise<void> {
return Promise.resolve();
}
forceFlush(): Promise<void> {
return Promise.resolve();
}
}
Update your instrumentation
file to include this processor before the default one.
const loggerProvider = new LoggerProvider({
resource: resourceFromAttributes({
'service.name': '<<SERVICE_NAME>>',
}),
processors: [
new CustomAttributesProcessor(),
new SimpleLogRecordProcessor(
new OTLPLogExporter({ url: '<<SIGNOZ_COLLECTOR_URL>>/v1/logs' })
),
],
});
Now every log exported will include these additional contextual attributes.

Demo Application
Check out this Sample React Application that demonstrates sending logs to SigNoz.
Last updated: August 17, 2025
Edit on GitHub