Instrument a Resource with OpenTelemetry

View as Markdown

This tutorial sends structured OpenTelemetry (OTLP) logs from a Resource to the reserved telemetry Door. You will emit severity-tagged log records (from Rust with the nanocar guest library or from JavaScript with an OTLP/HTTP exporter), deploy, and read the structured severity badges in the Logs tab. It takes about fifteen minutes.

Every Resource can push OTLP logs to the telemetry Door with no network configuration; the Door is host-provided. Raw stdout and stderr capture always works alongside it. See Telemetry for the reference.

Prerequisites

  • A deployed Resource. This tutorial uses acme with an api Resource.
  • The hyjal CLI installed and logged in.
  • The toolchain for your lane: Rust with cargo component, or Node.js for the JS lane.

1. Emit structured logs

Pick the lane that matches your Resource.

Rust with nanocar

Add the nanocar guest library and initialize it once at the top of your handler. It routes OTLP log records to the telemetry Door. Emit records with a severity and message.

1use nanocar::{log, Severity};
2
3fn handle_request() {
4 nanocar::init();
5
6 log(Severity::Info, "request accepted", &[("route", "/orders")]);
7
8 match process() {
9 Ok(_) => log(Severity::Info, "order processed", &[]),
10 Err(e) => log(Severity::Error, "order failed", &[("error", &e.to_string())]),
11 }
12}

Each record carries a severity (Info, Warn, Error, and so on) and optional key-value attributes. The severity is what renders as a badge in the Logs table.

JavaScript with an OTLP exporter

On the JS lane, point any OTLP/HTTP logs exporter at the telemetry Door. The Door endpoint is available to the instance as HYJAL_TELEMETRY_ENDPOINT.

1import { LoggerProvider, SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
2import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
3import { SeverityNumber } from "@opentelemetry/api-logs";
4
5const provider = new LoggerProvider();
6provider.addLogRecordProcessor(
7 new SimpleLogRecordProcessor(
8 new OTLPLogExporter({ url: process.env.HYJAL_TELEMETRY_ENDPOINT }),
9 ),
10);
11const logger = provider.getLogger("api");
12
13export default {
14 async fetch(request) {
15 logger.emit({
16 severityNumber: SeverityNumber.INFO,
17 body: "request accepted",
18 attributes: { route: new URL(request.url).pathname },
19 });
20 return new Response("ok");
21 },
22};

The exporter posts OTLP over HTTP to the Door; the severity number maps to the badge shown in the Logs table.

2. Deploy

Deploy the Resource. No egress allowlist entry is needed for the telemetry Door: it is a host-provided capability, not an external host.

$$ hyjal deploy
$Building resource api...
$ cargo component build āœ“
$Uploading artifact... digest sha256:b83f2c…4a10
$Applying policy... āœ“
$Flipping route... āœ“
$
$Deployed acme/api
$ https://api--acme.hyjal.cloud

3. Generate traffic

Send a few requests so the instance emits records.

$$ curl -s https://api--acme.hyjal.cloud/orders
$ok

4. Read severity badges in the Logs

Open the Logs tab in the Console, or stream from the CLI. Structured OTLP records render with a severity badge (INFO, WARN, ERROR) while raw output keeps honest STDOUT and STDERR badges.

$$ hyjal logs -f --resource api
$[16:04:22] GET /orders 200 18ms
$[16:04:22] INFO request accepted route=/orders
$[16:04:22] INFO order processed
$[16:07:01] GET /orders 500 22ms
$[16:07:01] ERROR order failed error=timeout contacting payment API

Each structured record is correlated with the request that produced it. Filter the table by method in the Console to isolate the requests you care about; the severity badges make error records scannable at a glance.

What you built

  • A Resource that emits structured OTLP logs to the telemetry Door, from Rust with nanocar or from JavaScript with an OTLP exporter.
  • Severity-tagged records rendered as badges in the Logs table.
  • Structured telemetry alongside honest stdout and stderr capture, with no egress configuration.

Next steps

  • Telemetry: the OTLP contract and the telemetry Door.
  • Logs: the request timeline, search, and filters.
  • Stats and metering: request counts, compute time, and peak memory.