> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rootprint.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Send logs from Zig

> Ship Zig logs to Rootprint with the opentelemetry-sdk std.log bridge over OTLP HTTP.

<Warning>
  The `opentelemetry-sdk` for Zig is in **alpha** (v0.1.1, Zig 0.15.2). It is not yet
  proven in production. Expect breaking changes between releases.
</Warning>

Rootprint accepts OpenTelemetry logs over OTLP HTTP. The Zig SDK's `std.log` bridge routes all
standard library log calls to OpenTelemetry without changing a single call site. Records land in
the OTEL logs index pinned by your ingest API key (`otel-logs-v0_9` in these examples).

## Prerequisites

* A running Rootprint instance and its base URL — you'll substitute it for `<your-rootprint>`.
* Zig ≥ 0.15.2.
* An **ingest API key** scoped to your target index. In **Settings → API keys**, click **Create ingest key**, give it a name, and pick the index (`otel-logs-v0_9` for the examples here). See [API keys](/api/overview).

## Setup

<Steps>
  <Step title="Add the SDK to your project">
    Requires Zig ≥ 0.15.2. Run this in your project root:

    ```bash theme={"theme":"github-light"}
    zig fetch --save "git+https://github.com/zig-o11y/opentelemetry-sdk#v0.1.1"
    ```

    Then add these lines to `build.zig` after your `exe` declaration:

    ```zig theme={"theme":"github-light"}
    const otel_sdk = b.dependency("opentelemetry", .{
        .target = target,
        .optimize = optimize,
    });
    exe.root_module.addImport("opentelemetry-sdk", otel_sdk.module("sdk"));
    ```

    The dependency key `opentelemetry` matches the SDK's package name in its
    `build.zig.zon`; the import alias `opentelemetry-sdk` is what your code will
    `@import`.
  </Step>

  <Step title="Set environment variables">
    ```bash theme={"theme":"github-light"}
    export OTEL_SERVICE_NAME=my-zig-service
    export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://<your-rootprint>/v1/logs
    export OTEL_EXPORTER_OTLP_LOGS_HEADERS=Authorization=Bearer%20<your-ingest-token>
    ```

    <Warning>The `%20` after `Bearer` is required. OTEL expects URL-encoded header values.</Warning>
  </Step>

  <Step title="Minimal working example">
    <Expandable title="src/main.zig">
      ```zig theme={"theme":"github-light"}
      const std = @import("std");
      const sdk = @import("opentelemetry-sdk");

      pub const std_options: std.Options = .{
          .logFn = sdk.logs.std_log_bridge.logFn,
      };

      pub fn main() !void {
          var gpa = std.heap.GeneralPurposeAllocator(.{}){};
          defer _ = gpa.deinit();
          const allocator = gpa.allocator();

          // OTLP exporter — reads OTEL_EXPORTER_OTLP_* env vars
          var otlp_config = try sdk.otlp.ConfigOptions.init(allocator);
          defer otlp_config.deinit();

          var otlp_exporter = try sdk.logs.OTLPExporter.init(allocator, otlp_config);
          defer otlp_exporter.deinit();
          const exporter = otlp_exporter.asLogRecordExporter();

          // Wire the exporter into a processor
          var simple_processor = sdk.logs.SimpleLogRecordProcessor.init(allocator, exporter);
          const processor = simple_processor.asLogRecordProcessor();

          // Logger provider with the processor attached
          var provider = try sdk.logs.LoggerProvider.init(allocator, null);
          defer provider.deinit();
          try provider.addLogRecordProcessor(processor);

          // Route std.log calls through OpenTelemetry
          try sdk.logs.std_log_bridge.configure(.{
              .provider = provider,
              .also_log_to_stderr = true,
          });
          defer sdk.logs.std_log_bridge.shutdown();

          std.log.info("Hello from Zig to Rootprint", .{});

          try provider.shutdown();
      }
      ```
    </Expandable>

    Save as `src/main.zig` and run `zig build run`. The bridge reads the endpoint and auth header
    from the environment variables above.
  </Step>

  <Step title="Verify in Rootprint">
    Open Search, filter on `service_name:my-zig-service`, and your record should appear within
    \~2 seconds.
  </Step>
</Steps>

## Structured logging

The `std.log` bridge maps Zig log levels to OpenTelemetry severity numbers automatically:

| Zig level | OTel severity |
| --------- | ------------- |
| `debug`   | DEBUG (5)     |
| `info`    | INFO (9)      |
| `warn`    | WARN (13)     |
| `err`     | ERROR (17)    |

Log messages and their format arguments become the log record **body**. Unlike Go's `slog.With`,
the `std.log` API does not support structured key/value attributes. Format args are interpolated
into the message string.

```zig theme={"theme":"github-light"}
std.log.info("user signed up: {s} plan={s}", .{ user_id, plan });
```

For structured attributes, use the direct SDK API: see the
[examples/logs/](https://github.com/zig-o11y/opentelemetry-sdk/tree/main/examples/logs) folder
in the SDK repository.
