Skip to content

Send your first logs

In this tutorial you create a project ingest key, send a few JSON log lines with curl, and find them in Pulse.

Pulse is observability for the teams already working in Orbit. Telemetry belongs to an Orbit project: who can read it is decided by that project’s roles, and what a sender can write is decided by an ingest key that belongs to the project.

  1. A project administrator opens Pulse for the project and creates an ingest key. Give it a name that says who uses it, such as checkout-service.

  2. Optionally set the key’s rate limit (records per minute; the default is 60,000) and maximum body size (default 5 MiB, at most 16 MiB).

  3. Copy the key. It is shown once; Pulse stores only a hash. A project can have at most 50 active keys. Revoking a key makes intake refuse it immediately.

The key decides the project. Anything in a payload that names a project is ignored, and a key from another project can never write here.

Post one JSON object, an array of objects, or newline-delimited objects to the JSON log intake. Send the key in the X-Pulse-Key header (Authorization: Bearer <key> also works).

Terminal
export INGEST_KEY=<your ingest key>
curl -sS -X POST "https://acme.orbit.inortix.com/api/v1/pulse/intake/logs" \
-H "X-Pulse-Key: $INGEST_KEY" \
-H "Content-Type: application/json" \
-d '[
{"message": "order created", "level": "info", "service": "checkout", "env": "staging", "version": "1.4.2", "host": "web-1"},
{"message": "payment gateway timeout", "level": "error", "service": "checkout", "env": "staging", "version": "1.4.2", "host": "web-1", "http": {"status_code": 504}}
]'

A successful call answers 202 with the counts:

Response
{"accepted": 2, "rejected": 0, "errors": []}

400 means nothing was accepted; the errors array says which record failed and why.

The first matching name in each row wins. Everything else is kept as an attribute, and nested objects are flattened into dotted keys (the example above stores http.status_code).

Meaning Accepted names
message message, msg, log. A message that is itself a JSON object is parsed into attributes.
time timestamp, @timestamp, date, time, ts (RFC 3339, or Unix seconds, milliseconds, microseconds or nanoseconds).
status status, level, severity, log.level, loglevel. Normalised to emergency, alert, critical, error, warn, notice, info, debug or trace; default info.
service service, service.name
host host, hostname, host.name
env env, environment, deployment.environment, deployment.environment.name
version version, service.version
source ddsource, source
trace and span ids trace_id, traceId, trace.id, dd.trace_id (decimal ids are converted to hex); the same pattern for span_id
tags ddtags ("k:v,k2:v2") or a tags object, stored as resource tags

Bounds: 256 attributes, 128 tags, keys up to 256 bytes, values up to 16 KiB, messages up to 64 KiB, nesting depth 8. Truncated records carry pulse.truncated: "true". A request holds at most 10,000 records.

If you already use OpenTelemetry, see Send telemetry with OpenTelemetry instead.

  1. Open Observability in the project and go to Logs. The default range is the last 15 minutes.

  2. Search for the errors of one service:

    Search
    service:checkout status:error

    The search uses Pulse’s one query syntax: see the query syntax reference. A syntax mistake is reported with its position.

  3. Use the facets next to the list (for example service or @http.status_code) with their counts. Clicking a value filters by it; any attribute or resource tag in an opened log can be filtered on or excluded in one click.

  4. Open a log to see its attribute tree, its trace (when it carries a trace id) and the surrounding logs from the same service and host.

  5. Turn on live tail to watch matching logs arrive. It uses the same query. One connection lasts up to 30 minutes, and at most four are allowed per user.

A project administrator can change the project’s settings:

  • Retention: 1 to 365 days. Each project keeps its own retention, and expired rows are removed automatically. Searches are clamped to the retention window.
  • Daily quotas for log records and for spans (per UTC day, across all keys), and a warning share between 50 and 99 percent (80 by default).

When a request crosses a quota, Pulse keeps the records that fit and rejects the rest; they are never queued. The reply says so (rejected and quota for JSON intake). Pulse notifies the project’s administrators in Orbit when the warning share is reached and again when the first record is rejected.

The Usage view shows today’s records against the quotas, stored records per day for 1 to 90 days, and the services that send the most, with links to their logs.

You see Meaning
An error status such as 403 The key is missing, revoked or invalid. A revoked key is refused at once.
429 with Retry-After The key’s records-per-minute budget was exceeded. The whole request is rejected and nothing is stored.
503 Pulse quota service unavailable The service that counts quotas is unavailable; nothing is stored.
Records missing Check the time: records outside the project’s retention window are rejected.