Skip to main content

Logging

reportEvent

The reportEvent utility provides a unified and structured way to log events and errors to both Datadog and Sentry. It supports both client-side and server-side logging and is designed to work seamlessly with Next.js (including API routes, middleware, and edge functions).

Prerequisites

To use this utility, you must have both Datadog Logs and Sentry configured in your application.

Datadog setup (client side)

Add the following to your _app.tsx or root component:

useEffect(() => {
if (process.env.NEXT_PUBLIC_ENVIRONMENT === "production") {
datadogLogs.init({
clientToken: env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN,
site: "datadoghq.eu",
service: "service-name", // e.g. "oeit-consumer-site"
env: "env-name", // e.g. "oeit-prod"
forwardErrorsToLogs: true,
sessionSampleRate: 100,
});
}
}, []);

Note: On the server, logs are output using the native console methods (e.g., console.error, console.warn, console.info), which are captured by log drains or observability platforms.

Sentry setup

Configure Sentry in all 3 contexts:

// sentry.client.config.js
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV,
});
// sentry.server.config.js
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV,
enabled: process.env.NODE_ENV === 'production',
});
// sentry.edge.config.js
init({
dsn: env.SENTRY_DSN,
tracesSampleRate: 1,
debug: false,
environment: env.VERCEL_ENV,
});

Basic Usage

Import

import { reportEvent } from '@krakentech/blueprint-utils/logging';

Example (client side)

reportEvent({
eventType: "meter_power_change",
description: "User requested a change in meter power capacity to 4.5kW",
severity: "info",
reportTo: "datadog",
meta: {
source: "MeterPowerCapacityChange"
},
extra: {
accountNumber
}
});

Example (server side)

reportEvent({
eventType: EventType.GraphQLError,
description: "CreateAccount mutation failed",
severity: "warning",
reportTo: "both",
error,
meta: {
source: "/api/create-account",
},
extra: {
mutation: "CreateAccount"
}
});

API Reference

reportEvent(options: LogContext): void

Parameters:
NameTypeRequiredDescription
reportTo"datadog" | "sentry" | "both"YesWhere to send the log.
eventTypestringYesUsed for filtering/categorization. Defaults to string, but can be replaced (see below).
descriptionstringYesHuman-readable summary.
severity'info' | 'warning' | 'error'NoDefaults to 'error'.
errorunknownNoOptional error to capture.
reqNextApiRequest | NextRequest | IncomingMessageNoOptional request to extract headers.
envstringNoUseful for multi-env logging.
servicestringNoMicroservice/package name.
versionstringNoGit SHA or version number.
metaRecord<string, string>NoTags, e.g. { source: "MyComponent" } on client or { source: "/api/create-account" } on server.
extraRecord<string, unknown>NoContextual data like { step: "Tariffs" } or mutation: "CreateAccount".

Event Types

You can pass any string as eventType, but we strongly recommend centralizing all event types in a shared enum or constant object to maintain consistency across your codebase.

Example enum you could use:

export enum EventType {
BlockedRequest = 'blocked_request',
GraphQLError = 'graphql_error',
GenericInfo = 'generic_info',
InvalidData = 'invalid_data',
MissingData = 'missing_data',
UnexpectedError = 'unexpected_error',
ValidationError = 'validation_error',
}

Enforcing eventType

You can also force eventType to accept a specific type. In order to do so, you just need to pass a custom type to reportEvent, like this:

reportEvent<CustomType>()

If you don't want to specify your custom type every time, you can re-export your reportEvent function by applying it once:

import { reportEvent as report } from "@krakentech/blueprint-utils/logging";

enum EventType {
BlockedRequest = 'blocked_request',
GraphQLError = 'graphql_error',
GenericInfo = 'generic_info',
InvalidData = 'invalid_data',
MissingData = 'missing_data',
UnexpectedError = 'unexpected_error',
ValidationError = 'validation_error'
}

export const reportEvent = report<EventType>;

Bonus tip If you want TypeScript to suggest your custom EventType values while still allowing arbitrary strings, you can define:

type CustomType = EventType | (string & {})

This way, you get:

  • ✅ Suggestions when using the enum or a shared set of strings.
  • ✅ Flexibility to pass dynamic/custom strings (even) at runtime.

Logging Levels

You can customize severity to signal the urgency or importance of the event:

reportEvent({
eventType: EventType.GenericInfo,
description: "User clicked CTA on pricing banner",
severity: "info",
reportTo: "datadog",
meta: { source: "PricingPage" },
extra: { accountNumber: "A-12345", ctaText: "Get a quote" },
});
reportEvent({
eventType: EventType.ValidationError,
description: "Validation failed on Onboarding review step",
severity: "warning",
reportTo: "sentry",
meta: { source: "ReviewStep" }
});
reportEvent({
eventType: EventType.UnhandledError,
description: "Something exploded",
severity: "error",
reportTo: "both",
error,
meta: { source: "_error.tsx" },
});

Best Practices

  • Use eventType consistently across your app. This enables filters and metrics in both Datadog and Sentry.
  • Avoid PII: never log personal information like names, emails, etc.
  • Use severity = "info" for harmless logs, severity = "warning" for recoverable or suspicious states, severity = "error" for actual breakages.
  • Always add meta.source to identify the origin of the log.
  • Add useful context in extra for debugging.
  • In pages/api, app/api, getServerSideProps or middleware , pass req to capture safe headers (user-agent, x-request-id, etc.).

Troubleshooting

Nothing shows in Datadog?

  • Check the browser devtools: is datadogLogs.logger.log() being called?
  • Ensure Datadog is correctly initialized in production only.
  • Console output is used as fallback in dev.

Nothing shows in Sentry?

  • Check that the right Sentry config is initialized based on environment.
  • Make sure the error is passed if it's an exception.
  • For non-errors, captureMessage() is used.

Summary

The reportEvent utility provides a centralized and consistent way to log events and errors from your application. It's lightweight, safe, and structured for observability platforms like Datadog and Sentry. Use it everywhere instead of console.log or direct calls to captureException.