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" }ormutation: "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 eventTypeconsistently 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.sourceto identify the origin of the log.
- Add useful context in extrafor debugging.
- In pages/api,app/api,getServerSidePropsormiddleware, passreqto 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 erroris 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.