Skip to content
Exlogare

Generic CI ingest

One endpoint for any CI/CD platform — Buildkite, AppVeyor, custom in-house tooling.

POST /api/ingest/log is the catch-all ingest endpoint. Use it when there is no dedicated route for your CI/CD engine — Buildkite, AppVeyor, GoCD, Concourse, Bamboo, custom in-house pipelines, ad-hoc shell scripts.

If your integration lives in a shell script, the fastest path is the Exlogare CLI: exl ingest sends the same fields to /api/ingest/log, but reads logs from a file/stdin and builds the JSON for you.

exl ingest --provider buildkite --project myorg/myrepo --status failed --log-file build.log

Required fields

FieldTypeNotes
providerstringCI vendor label. Anything reasonable works — buildkite, AppVeyor, GitHub Actions, My CI 1.0 are all accepted. We auto-normalise to a lowercase slug (max 32 chars): spaces, slashes, parentheses and other punctuation become _, runs are collapsed, and the result is trimmed to start/end with [a-z0-9].
projectstringProject / repo identifier for grouping.
statusstringLowercase normalised status — see “Statuses” below.
logstringThe failed-step log, up to 10 MiB.

Optional metadata

FieldNotes
pipeline_idA unique identifier for the run inside the provider (run id / build id / workflow id).
job_idIdentifier for the failing step / job inside the run.
job_nameHuman-readable step name.
branchSource branch / ref.
commit_shaCommit hash.
pipeline_urlDeep link back to the build page.
build_numberDisplay number (e.g. #482).

We use pipeline_id + job_id for idempotent dedupe — if your CI has them, please send them.

Statuses

We accept (and don’t bounce) any string but recognise: success, passed, ok, failed, failure, error, errored, cancelled, canceled, timeout, timedout, aborted, killed, running, pending, queued, skipped, blocked.

Unknown values are accepted and surfaced verbatim in the dashboard.

Minimal example

With the CLI:

exl ingest \
  --provider buildkite \
  --project myorg/myrepo \
  --status failed \
  --log-file build.log

The same request directly against the API:

curl -fsS -X POST https://api.exlogare.net/api/ingest/log \
  -H "Authorization: Bearer $EXLOGARE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "buildkite",
    "project":  "myorg/myrepo",
    "status":   "failed",
    "log":      "...build log..."
  }'

Buildkite example

# .buildkite/pipeline.yml
steps:
  - label: ":hammer: test"
    command: |
      set -o pipefail
      pnpm test 2>&1 | tee /tmp/build.log

  - wait: ~
    continue_on_failure: true

  - label: ":satellite: send-failure-log"
    if: build.state == "failed"
    command: |
      curl -fsS -X POST https://api.exlogare.net/api/ingest/log \
        -H "Authorization: Bearer $$EXLOGARE_TOKEN" \
        -H "Content-Type: application/json" \
        -d "$(jq -n \
          --arg pid "$BUILDKITE_BUILD_ID" \
          --arg jid "$BUILDKITE_JOB_ID" \
          --arg br  "$BUILDKITE_BRANCH" \
          --arg sha "$BUILDKITE_COMMIT" \
          --arg url "$BUILDKITE_BUILD_URL" \
          --arg log "$(cat /tmp/build.log)" \
          '{provider:"buildkite", project:"$BUILDKITE_PIPELINE_SLUG", pipeline_id:$pid, job_id:$jid, status:"failed", branch:$br, commit_sha:$sha, pipeline_url:$url, log:$log}')"

AppVeyor example

# appveyor.yml
on_failure:
  - sh: |
      curl -fsS -X POST https://api.exlogare.net/api/ingest/log \
        -H "Authorization: Bearer $EXLOGARE_TOKEN" \
        -H "Content-Type: application/json" \
        -d "$(jq -n \
          --arg pid "$APPVEYOR_BUILD_ID" \
          --arg br  "$APPVEYOR_REPO_BRANCH" \
          --arg sha "$APPVEYOR_REPO_COMMIT" \
          --arg log "$(cat build.log)" \
          '{provider:"appveyor", project:"$APPVEYOR_PROJECT_SLUG", pipeline_id:$pid, status:"failed", branch:$br, commit_sha:$sha, log:$log}')"

Common CI env-var mapping

pipeline_idjob_idbranchcommit_sha
BuildkiteBUILDKITE_BUILD_IDBUILDKITE_JOB_IDBUILDKITE_BRANCHBUILDKITE_COMMIT
AppVeyorAPPVEYOR_BUILD_IDAPPVEYOR_REPO_BRANCHAPPVEYOR_REPO_COMMIT
GoCDGO_PIPELINE_COUNTERGO_STAGE_COUNTERGO_REVISION
ConcourseBUILD_IDBUILD_JOB_NAME
Bamboobamboo_buildKeybamboo_planKeybamboo_planRepository_branchbamboo_planRepository_revision

If your engine isn’t listed, just use whatever values you have.