← Back to blog
Guide 4 min read 炬鲸团队

Onboard Your Logs in Five Minutes: From Token to First Result

A complete five-minute path: create an environment, grab the ingest token, push your first line with curl, verify in the console, then move to Fluent Bit and Kubernetes for production, with copy-paste commands.

Ingestion is the first hurdle of any logging platform, and it's where most teams stall — agent configs, index templates, auth between daemons. JUJING OBSERVE keeps the whole thing deliberately simple: one token per environment, POST JSON Lines, done. Here's the full path from zero to your first record, under five minutes.

Step 1: create an environment and grab the ingest token

After logging in, create an environment (say, prod) under Environments. The system generates a dedicated ingest token for it. Tokens are separate from your login password and scoped one-per-environment; a tenant can have multiple environments (prod / uat / dev), and switching environments in the top bar filters search, monitoring, and export accordingly.

This separation matters: the token your collector ships with can be revoked without touching anyone's login, and each environment's data stays addressable on its own. Copy the token — it's the credential for every command below.

Step 2: push your first line with curl

The ingest endpoint is POST /api/ob/logs/jsonline. Send X-Ingest-Token in the header and JSON Lines (NDJSON) in the body, one object per line. Verify with curl:

export OB_API=https://ob.jjhub.cn
export OB_INGEST_TOKEN='your_token'

echo '{"log.file.path":"/var/log/app/service.log","content":"2026-07-26 17:44:46.159  ERROR [t1] [main] demo.App:run():1 : hi","k8s_label_ob-name":"demo"}'   | curl -X POST "$OB_API/api/ob/logs/jsonline"     -H 'Content-Type: application/x-ndjson'     -H "X-Ingest-Token: $OB_INGEST_TOKEN"     --data-binary @-

A response of {"code":0,"message":"success","data":null} means it worked. A few notes that save debugging time:

  • If log.file.path ends with service.log it's treated as an application log; tracing.log routes to trace data. Get this suffix wrong and records land in the wrong view.
  • content should use Log4j2-style text (time, level, [traceId], thread name) so the platform can parse the fields instead of storing one opaque blob.
  • Add the dimension labels k8s_label_ob-company / k8s_label_ob-project / k8s_label_ob-name to aggregate by company, project, and service — cheap to set once, painful to retrofit.

Step 3: verify in the console and search

Back in the console, switch to the environment you created and open the Service page — the ERROR line should be there. Filter with a SQL-like condition: level="ERROR" and serviceName="demo". Timeline, record details, and traceId drill-down are all on this page. At this point your ingest path is fully working, and everything after is just plumbing to make it durable at scale.

Going further: Fluent Bit and Kubernetes

Don't run raw curl in production. Use Fluent Bit with tail + HTTP output:

[INPUT]
    Name   tail
    Path   /var/log/app/service.log
    Tag    service

[OUTPUT]
    Name   http
    Match  *
    Host   ob.jjhub.cn
    Port   443
    URI    /api/ob/logs/jsonline
    Format json_lines
    Header X-Ingest-Token ${OB_INGEST_TOKEN}

On Kubernetes, label your pods ob-company / ob-project / ob-name and collect via EmptyDir + sidecar or a DaemonSet. Spring Boot apps write service.log / tracing.log to disk and have an agent push them; low-volume services can POST directly over HTTP. Once connected, create an alert rule right away (for example, more than 20 ERROR lines in 5 minutes) so the platform notifies you before the problem grows — logs only help if someone looks, and an alert is what makes that reliable.

Troubleshooting and the OTLP path

If your first record doesn't show up, work through three things in order. First, confirm you're viewing the same environment the token belongs to — data is scoped per environment, and it's easy to be staring at dev while your curl hit prod. Second, check the log.file.path suffix: service.log goes to the Service view, tracing.log to Tracing; a mismatched suffix drops records into a view you aren't looking at. Third, verify the token is present in the header and wasn't mangled by shell quoting — a missing or truncated token returns 401 with code=-1.

If your services already emit OpenTelemetry, you can skip the custom line format entirely. JUJING OBSERVE accepts OTLP/HTTP JSON at POST /api/otlp/v1/logs and /api/otlp/v1/traces with the same X-Ingest-Token auth, so an existing OTLP collector can forward both signals by changing a single endpoint rather than re-encoding every field by hand. Whichever path you pick, do the five-minute curl test first — it isolates the platform from your collector, so when something breaks later you already know which half of the pipeline to blame.