npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aws-blocks/bb-metrics

v0.1.1

Published

Custom application metrics backed by Amazon CloudWatch (via Embedded Metric Format).

Downloads

1,678

Readme

Metrics

Custom application metrics backed by Amazon CloudWatch (via Embedded Metric Format).

When to use: You need to track numeric measurements over time — request counts, error rates, latency, queue depths, business KPIs. Good for dashboards, alarms, and operational visibility.

When NOT to use: If you need structured log output, use Logging. If you need distributed request tracing, use Tracing. If you need to store time-series data for querying, use Database or DistributedTable.

API

const metrics = new Metrics(scope, id, options?)

| Method | Returns | Description | |--------|---------|-------------| | emit(name, value, options?) | void | Record a single metric data point via EMF. | | emitBatch(metrics) | void | Record multiple metric data points in one EMF document (max 100). | | flush() | void | No-op (EMF writes are immediate). Provided for interface compatibility. | | child(dimensions) | MetricsEmitter | Create a child emitter with inherited namespace and merged dimensions. | | Metrics.fromExisting(namespace) | ExternalMetricsRef | Wrap a pre-existing CloudWatch namespace. |

Options

| Option | Type | Description | |--------|------|-------------| | namespace | string | CloudWatch namespace. Defaults to scope.fullId. | | defaultDimensions | Record<string, string> | Dimensions applied to every emit. Per-emit dimensions merge on top (per-emit wins on conflict). | | metrics | ExternalMetricsRef | Wrap an existing CloudWatch namespace instead of creating one. When set, namespace is ignored. | | logger | ChildLogger | Optional logger for internal operations. When omitted, a default Logger at error level is created. |

EmitOptions

| Option | Type | Description | |--------|------|-------------| | unit | MetricUnit | Unit of the metric value. Defaults to 'None'. | | dimensions | Record<string, string> | Dimensions for this data point (max 30 total including defaults). | | timestamp | Date | Timestamp for the data point. Defaults to now. | | resolution | MetricResolution | 'standard' (60s, default) or 'high' (1s, higher cost). |

MetricUnit

type MetricUnit =
  | 'Count' | 'Seconds' | 'Milliseconds' | 'Microseconds'
  | 'Bytes' | 'Kilobytes' | 'Megabytes' | 'Gigabytes'
  | 'Percent' | 'Bits/Second' | 'None';

Error Handling

import { isBlocksError } from '@aws-blocks/core';
import { MetricsErrors } from '@aws-blocks/bb-metrics';

try {
  metrics.emit('', 1);
} catch (e: unknown) {
  if (isBlocksError(e, MetricsErrors.InvalidMetricName)) {
    // metric name is empty or exceeds 1024 characters
  }
}

| Error | Condition | |-------|-----------| | MetricsErrors.InvalidMetricName | Metric name is empty or exceeds 1024 characters. | | MetricsErrors.InvalidDimensions | Dimensions exceed 30 entries, or contain empty keys/values, or key/value exceeds 1024 chars. | | MetricsErrors.BatchTooLarge | Batch contains more than 100 metrics. | | MetricsErrors.InvalidNamespace | Namespace is empty, too long, contains invalid characters, or uses reserved AWS/ prefix. |

Examples

Basic Usage

import { Scope, ApiNamespace } from '@aws-blocks/blocks';
import { Metrics } from '@aws-blocks/bb-metrics';

const scope = new Scope('my-app');
const metrics = new Metrics(scope, 'appMetrics', {
  namespace: 'MyApp/Orders',
  defaultDimensions: { service: 'orders' },
});

export const api = new ApiNamespace(scope, 'api', (context) => ({
  async handleRequest() {
    metrics.emit('RequestCount', 1, { unit: 'Count' });
    metrics.emit('Latency', 42, { unit: 'Milliseconds' });
    return { ok: true };
  },
}));

Emit with Dimensions

metrics.emit('RequestCount', 1, {
  unit: 'Count',
  dimensions: { endpoint: '/api/users', method: 'GET' },
});

Batch Emit

metrics.emitBatch([
  { name: 'RequestCount', value: 1, unit: 'Count' },
  { name: 'Latency', value: 42, unit: 'Milliseconds' },
  { name: 'ErrorCount', value: 0, unit: 'Count' },
]);

Child Emitters (Scoped Dimensions)

const requestMetrics = metrics.child({ endpoint: '/api/users', method: 'GET' });
requestMetrics.emit('RequestCount', 1);
requestMetrics.emit('Latency', 35, { unit: 'Milliseconds' });

Children inherit the parent's namespace and default dimensions, merging their own on top. Children can be nested arbitrarily.

Wrapping an Existing Namespace

const legacy = new Metrics(scope, 'legacy', {
  metrics: Metrics.fromExisting('MyOrg/SharedMetrics'),
});
legacy.emit('MigrationCount', 1);

High-Resolution Metrics

metrics.emit('CPUSpike', 95.2, {
  unit: 'Percent',
  resolution: 'high', // 1-second aggregation
});

CDK Configuration

The CDK construct creates no AWS resources. It only resolves and exposes the namespace and defaultDimensions as readonly properties for CDK-time consumers.

EMF uses CloudWatch Logs (which Lambda already has permissions for), so no environment variable or cloudwatch:PutMetricData IAM grant is needed. CloudWatch namespaces are created implicitly on first metric data point arrival.

Synchronous API Rationale

All metric methods return void, not Promise<void>. This is intentional:

  • EMF writes to stdoutprocess.stdout.write() is a synchronous, non-blocking call on Linux. The kernel buffers the write and Lambda's logging agent captures it asynchronously.
  • No network I/O — Unlike PutMetricData (which makes an HTTP call to CloudWatch), EMF piggybacks on CloudWatch Logs, which Lambda already streams. There is nothing to await.
  • Zero overhead — Returning a Promise would add microtask scheduling overhead for zero benefit. Metrics should be as cheap as a console.log.
  • Fire-and-forget semantics — Metrics are observability data, not business-critical writes. If a metric fails to emit (e.g., stdout is closed), it should not crash the request.

This design means you can emit metrics anywhere — in hot loops, synchronous callbacks, or error handlers — without worrying about async context or unhandled promise rejections.

Best Practices

  • Keep dimension cardinality low (avoid user IDs or request IDs as dimensions)
  • Use consistent metric names across your application
  • Use defaultDimensions for shared context (service name, environment)
  • Prefer emitBatch when recording multiple metrics in a single request
  • Use units to enable automatic conversions in CloudWatch dashboards
  • Use child() to avoid repeating dimensions across related metrics

Scaling & Cost (AWS)

  • Ingestion: CloudWatch accepts unlimited metrics via EMF — no API call limits
  • Standard resolution (60s): Retained for 15 days at full resolution, then aggregated
  • High resolution (1s): Retained for 3 hours at full resolution, then aggregated
  • Cost: Scales with unique metric name + dimension combinations (~$0.30/metric/month)
  • Latency: EMF adds zero latency to the request (stdout write is non-blocking)

Local Development

Metrics are written as EMF JSON to stdout — the same format as AWS. In local dev, you can see metric emissions in the terminal output. No disk persistence — metrics are ephemeral locally (unlike KVStore or DistributedTable which persist to .bb-data/).

Delete nothing to reset — there's no local state to clear.