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:
Name | Type | Required | Description |
---|---|---|---|
reportTo | "datadog" | "sentry" | "both" | Yes | Where to send the log. |
eventType | string | Yes | Used for filtering/categorization. Defaults to string , but can be replaced (see below). |
description | string | Yes | Human-readable summary. |
severity | 'info' | 'warning' | 'error' | No | Defaults to 'error' . |
error | unknown | No | Optional error to capture. |
req | NextApiRequest | NextRequest | IncomingMessage | No | Optional request to extract headers. |
env | string | No | Useful for multi-env logging. |
service | string | No | Microservice/package name. |
version | string | No | Git SHA or version number. |
meta | Record<string, string> | No | Tags, e.g. { source: "MyComponent" } on client or { source: "/api/create-account" } on server. |
extra | Record<string, unknown> | No | Contextual 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
ormiddleware
, passreq
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
.