npm.io
0.2.1 • Published 5d ago

@autofleet/metrics

Licence
Proprietary
Version
0.2.1
Deps
0
Size
44 kB
Vulns
0
Weekly
408

@autofleet/metrics

Metric transports for Autofleet microservices.

// In your service: lib/metrics.ts (or wherever you wire singletons)
const { createMetricsClient } = require('@autofleet/metrics');
const logger = require('../logger');

const dogstatsd = createMetricsClient({ logger });
module.exports = { dogstatsd };

// At emit sites
const { dogstatsd } = require('./lib/metrics');
dogstatsd.increment('vehicle.data.locations.writes', 1, { source: 'motorq' });
dogstatsd.gauge('vehicle.data.events.has_recent_data', 1);

No app-side setup needed in Autofleet pods — the Datadog admission webhook injects dd-trace and the package resolves it eagerly when createMetricsClient() runs. Outside the cluster, see Using outside the cluster.

Where this package works

Context Behaviour
In-cluster pod with global.datadogEnabled: true Full functionality, no app-side config. Metrics flow over UDS to the node-local DD Agent; env / service / version tags are auto-applied. See How dd-trace gets into the pod for the mechanism.
Local dev, CI, unit tests Safe by default. If dd-trace isn't loadable → the package returns its own no-op stub. If dd-trace IS loadable but never had tracer.init() called (e.g., workspaces with autoInstallPeers: true) → dd-trace's own NoopDogStatsDClient takes over, calls succeed silently, no metrics get emitted. Either way: no errors, nothing leaks.
Other contexts (non-k8s pods, Lambdas, CLI scripts) Works if you set up dd-trace yourself. See Using outside the cluster.

Boot log caveat: instance loaded means tracer.dogstatsd exists on the loaded module — not that the agent is reachable or tracer.init() ran. If metrics aren't flowing despite instance loaded, verify tracer.init() was called and DD_AGENT_HOST / DD_DOGSTATSD_URL are set.

Installation

Inside autorepo (other workspace packages):

pnpm add @autofleet/metrics --filter @autofleet/<service-name>

Outside autorepo (standalone service repos: vehicle-ms, vld-ms, vehicle-search-ms, etc.):

npm install @autofleet/metrics

For beta versions:

npm install @autofleet/metrics@beta

Public API

Export Purpose
createMetricsClient(options?) Resolves the dd-trace dogstatsd client (or a no-op stub), emits a one-time boot log, returns the client. Call once per app, typically in lib/metrics.ts.
MetricsClient (type) The shape returned — the stable subset of dd-trace's tracer.DogStatsD interface (see Supported methods).
MetricsClientOptions (type) { logger?, debug? } — see Boot logging.
MetricsLogger (type) The logger shape any transport's logger option accepts: { info, warn }. @autofleet/logger satisfies it as-is.

Underscore-prefixed names (_tryLoad, _logBootSummary, _LoadResult) are exported only for the package's own tests. Don't import them.

createMetricsClient() returns the raw tracer.dogstatsd surface — call sites using it directly are coupled to dd-trace's API shape. To keep call sites clean and metric names + tags consistent, hold the client in a service-local module and define typed wrapper functions on top:

// In your service: lib/metrics.ts
import { createMetricsClient } from '@autofleet/metrics';
import logger from '../logger';

const dogstatsd = createMetricsClient({ logger });

const LOCATIONS_WRITES = 'vehicle.data.locations.writes';

export function recordLocationWrite(source?: string): void {
  dogstatsd.increment(LOCATIONS_WRITES, 1, { source: source ?? 'unknown' });
}

Then call recordLocationWrite(source) at emit sites. This keeps metric names + tag shapes in one place per service, and lets you swap the transport (e.g. add an HTTP client for non-pod contexts) without touching call sites.

createMetricsClient() emits one boot log when called: info if dd-trace's dogstatsd instance loaded, warn if it fell back to no-op. To surface it, pass a logger:

const { createMetricsClient } = require('@autofleet/metrics');
const logger = require('../logger');

const dogstatsd = createMetricsClient({
  logger,                                       // any { info, warn } pair; @autofleet/logger works as-is
  debug: process.env.LOG_LEVEL === 'debug',
});
Option Type Effect
logger { info(msg, meta?), warn(msg, meta?) } Receives the boot log. Omitting it leaves the package silent (no console output).
debug boolean (default false) When true, the boot log's meta includes DD_AGENT_HOST, DD_DOGSTATSD_URL, DD_ENV, DD_SERVICE, DD_VERSION — useful for triaging the no-op fallback (a missing DD_DOGSTATSD_URL points at admission webhook misconfiguration).

Each call fires its own boot log. Calling createMetricsClient() more than once in a process is fine but uncommon — typical pattern is one call per app, held in lib/metrics.ts.

Using outside the cluster

If you're not running in an Autofleet pod, provide what the admission webhook would have, by hand:

npm install dd-trace
// At the very top of your entry file, before any other require:
const tracer = require('dd-trace').init({
  service: 'my-service',
  env: process.env.NODE_ENV,
});

Set DD_AGENT_HOST (or DD_DOGSTATSD_URL) so the tracer can reach an agent. From there, createMetricsClient() works the same way as in-cluster. See element-adapter/src/datadog/index.ts for a working example.

Useful commands

For working on this package inside autorepo:

pnpm nx test metrics
pnpm nx build metrics
pnpm nx lint metrics
pnpm nx typecheck metrics

Technical details

How dd-trace gets into the pod

The Datadog Cluster Agent's admission webhook mutates eligible pods at admission time and ships a pre-initialised dd-trace with them. Useful to know when debugging "why did my pod land on the no-op fallback."

Trigger. Pods labelled admission.datadoghq.com/enabled: "true" get mutated. The base microservice chart sets that label when global.datadogEnabled is true (base-microservice/templates/deployment.yaml).

What gets added to the pod:

  • Two init containers copy dd-trace (currently v5.24.0) into /opt/datadog/apm/library/js and install an LD_PRELOAD shim that pre-loads it at Node startup.
  • App container env vars: DD_SERVICE / DD_ENV / DD_VERSION (from tags.datadoghq.com/* labels for Unified Service Tagging), DD_AGENT_HOST (from status.hostIP), DD_DOGSTATSD_URL=unix:///var/run/datadog/dsd.socket, DD_TRACE_AGENT_URL=unix:///var/run/datadog/apm.socket, plus LD_PRELOAD.
  • Hostpath mount of /var/run/datadog so the app reaches the node-local DD Agent over Unix sockets.

By the time application code runs, require('dd-trace') returns an already-initialised tracer — we never call tracer.init(). APM tracing, runtime metrics, log correlation, and tracer.dogstatsd all work with no app-side config.

This package's loader. Tries require('dd-trace') first (matches the LD_PRELOAD'd instance or a consumer's own install), then /opt/datadog/apm/library/js/node_modules/dd-trace as a fallback. Both fail → no-op fallback. If a pod unexpectedly lands on the no-op fallback, check that admission.datadoghq.com/enabled: "true" is set and the DD_* env vars made it in (kubectl describe pod ...).

Supported methods

tracer.dogstatsd exposes a subset of the DogStatsD protocol. The package's MetricsClient exposes the stable subset — see dd-trace's DogStatsD interface for the source of truth.

Method dd-trace This package
increment / decrement
gauge
distribution
histogram
flush ✓ (beta) ✗ — omitted; dd-trace marks it experimental
set / timing / event / check ✗ — not in tracer.dogstatsd

distribution vs histogram: distributions aggregate server-side (DDSketch) so percentiles are globally accurate across hosts; histograms aggregate client-side per Agent. Prefer distribution when you need cross-host percentile accuracy or percentile-based alerts. Both are valid — DD doesn't deprecate either. See Datadog's distributions docs.

@autofleet/metrics vs hot-shots vs the DD HTTP API
This package (dd-trace) hot-shots DD HTTP API
New dependency none (admission-injected) yes none
Transport UDS (auto from DD_DOGSTATSD_URL) UDP (default) HTTPS
env/service/version tagging automatic manual globalTags manual
Methods increment / decrement / gauge / distribution / histogram + set / timing / event / check full metrics submit API
Best for in-cluster Autofleet pods, or anywhere dd-trace is already initialised needs set / timing / event / check outside k8s / CI / one-shot scripts

Takeaway: if you're in a pod, use this package. If you need a method dd-trace doesn't expose, reach for hot-shots. If dd-trace isn't an option (Lambda, CLI, external worker), use the HTTP API — or file an issue so we can build an HTTP transport here.

Keywords