Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

JSON Log Line Parser

observability.parse_json_logs

ProductionBounded custom (Class B)Deterministicstrictfastv1.0.0
File inputNo network

Overview

You send newline-delimited JSON and we return one record per line, a report of the lines that did not parse, and a census of which keys appear how often and with which types. Key discovery is bounded: past the tracked-key cap we stop and tell you the line we stopped on, rather than returning a report as unbounded as the log that produced it. Distinct values are collected only for fields you name, so a free-form message field never becomes a content dump. We hold nothing, forward nothing and read no clock.

A JSON validator tells you whether a line parses; it does not tell you that 40 percent of your lines are missing the trace field or that duration arrives sometimes as a number and sometimes as a string.

Reliability

Fully deterministic: the same body and options always give you the same records and the same census, independent of locale, default time zone and default charset. Numbers are preserved exactly as written rather than passed through a binary double. Failures, none worth retrying unchanged: OBS_JSON_LOGS_INPUT_MISSING means neither logs nor fileRef arrived, so send one of them. OBS_JSON_LOGS_INPUT_INVALID means a property had the wrong type or the body was empty, so check the payload shape. OBS_JSON_LOGS_INPUT_TOO_LARGE means the inline body went past 2097152 bytes, so upload it and pass a file reference instead. OBS_JSON_LOGS_FILE_REF_NOT_ACCESSIBLE means the reference is not readable with these credentials, so upload the object again and use the new reference. OBS_JSON_LOGS_FILE_TOO_LARGE means the referenced object went past 10000000 bytes, so split it and call once per part. OBS_JSON_LOGS_LINE_LIMIT_EXCEEDED means the body carries more lines than your maxLines allows, so raise it up to 50000 or split the body. OBS_JSON_LOGS_DEPTH_EXCEEDED means a line nests deeper than maxDepth, and the answer names that line so you can look at it. OBS_JSON_LOGS_STATS_FIELD_LIMIT_EXCEEDED means statsFields named more than 16 keys, so ask for fewer. OBS_JSON_LOGS_LIMITS_INVALID means one of the limits fell outside its published range, so bring it back inside and send it again. OBS_JSON_LOGS_OPTION_UNSUPPORTED means a property is not one we accept, so drop it. OBS_JSON_LOGS_WORK_REFUSED means the projected work went past 16000000 units, and the answer carries both the projection and the budget. OBS_JSON_LOGS_OUTPUT_TOO_LARGE means the records would not fit the inline response ceiling, so set includeRecords false or send fewer lines.

Context footprint

Echoes every parsed record by default; set includeRecords false when you only want the census and the error report. A successful call costs 3 execution credits.

When to use it

When you hold JSON log lines and want records plus an honest, bounded picture of what the fields actually contain.

When your lines are logfmt, when you want a schema verdict, or when you need the content redacted.

Scope

Note
Read newline-delimited JSON logs into records and report, within published bounds, which keys appear how often and with which types.

Non-goals

  • Does not store, buffer, index or forward anything between calls
  • Does not scrape, poll or receive logs over a network
  • Does not redact or mask anything — send the text to security.redact_secrets first
  • Does not infer a cause, a root cause or a remediation from what it reads
  • Does not accept a caller-supplied regular expression on any field

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

parsing

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call3 credits

File handling

Accepts file_refProduces file_refMax input2 MBMax file size9.5 MB

File limits

Constraints this skill applies to your input and generated files. The “Limited by” column shows the static source of each cap; none of these can be raised by upgrading your plan.

LimitValueLimited by
Maximum size per input file9.5 MiBSkill and platform maximum
Maximum number of input files1Skill maximum

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
logsstringNoRequired unless fileRef is provided. Newline-delimited JSON, 1 to 2097152 UTF-8 bytes.
fileRefstringNoOptional Squillify file reference holding up to 10000000 bytes of JSON lines; omit it to parse the inline logs field.
limitsobjectNoClosed caps you can tighten; omit it for maxLines 50000, maxLineLength 16384, maxDepth 32, maxFieldsPerRecord 64, maxTrackedKeys 256, maxDistinctValues 20 and maxErrors 500.
levelFieldstringNoTop-level severity key of 1 to 128 code points; omit it for level.
statsFieldsarrayNoUp to 16 key names whose distinct values you want counted; omit it for an empty list.
includeRecordsbooleanNoWhether parsed records are echoed; omit it for true.

Output schema

FieldTypeRequiredDescription
recordsarrayYesOne {line, record} object per parsed line; empty when includeRecords is false.
errorsarrayYesUp to maxErrors parse defects, each a closed {line, column, code} object with optional key.
summaryobjectYesClosed run counters: lineCount, recordCount, blankLineCount, errorCount, errorsTruncated, truncated and sourceKind.
statsobjectYesClosed bounded census with recordCount, fields, levels, levelField, keysTruncated and keyDiscoveryStoppedAtLine.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"observability.parse_json_logs","input":{"logs":"{\"level\":\"info\",\"msg\":\"ok\"}\n"}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("observability.parse_json_logs", {"includeRecords":false,"logs":"{\"level\":\"info\",\"msg\":\"ok\",\"duration_ms\":12}\n{\"level\":\"error\",\"msg\":\"upstream refused\"}\n{\"level\":\"info\",\"msg\":\"ok\"}\n","statsFields":["level"]});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
OBS_JSON_LOGS_INPUT_MISSING400NoThe request payload failed this skill's input validation.
OBS_JSON_LOGS_INPUT_INVALID400NoThe request payload failed this skill's input validation.
OBS_JSON_LOGS_INPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_FILE_REF_NOT_ACCESSIBLE412NoThe input is valid but cannot be processed as-is.
OBS_JSON_LOGS_FILE_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_LINE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_DEPTH_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_STATS_FIELD_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_LIMITS_INVALID400NoThe request payload failed this skill's input validation.
OBS_JSON_LOGS_OPTION_UNSUPPORTED400NoThe skill does not support the requested variant.
OBS_JSON_LOGS_WORK_REFUSED429NoA size, quota, rate, or time limit was exceeded.
OBS_JSON_LOGS_OUTPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not store, buffer, index or forward anything between calls
  • Does not scrape, poll or receive logs over a network
  • Does not redact or mask anything — send the text to security.redact_secrets first
  • Does not infer a cause, a root cause or a remediation from what it reads
  • Does not accept a caller-supplied regular expression on any field
  • Reading logfmt text, which observability.parse_logfmt answers
  • Validating records against a schema, which schema.validate_ndjson answers

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "observability.parse_json_logs",
  "input": {
    "includeRecords": false,
    "logs": "{\"level\":\"info\",\"msg\":\"ok\",\"duration_ms\":12}\n{\"level\":\"error\",\"msg\":\"upstream refused\"}\n{\"level\":\"info\",\"msg\":\"ok\"}\n",
    "statsFields": [
      "level"
    ]
  }
}

Examples

Three lines with a level census and collected level values

Inputjson
{
  "includeRecords": false,
  "logs": "{\"level\":\"info\",\"msg\":\"ok\",\"duration_ms\":12}\n{\"level\":\"error\",\"msg\":\"upstream refused\"}\n{\"level\":\"info\",\"msg\":\"ok\"}\n",
  "statsFields": [
    "level"
  ]
}
Expected outputjson
{
  "summary": {
    "lineCount": 3,
    "recordCount": 3,
    "blankLineCount": 0,
    "errorCount": 0,
    "errorsTruncated": false,
    "truncated": false,
    "sourceKind": "INLINE"
  },
  "stats": {
    "recordCount": 3,
    "fields": [
      {
        "key": "level",
        "presentCount": 3,
        "presenceRatio": 1,
        "types": {
          "STRING": 3
        },
        "distinctValues": [
          {
            "count": 2,
            "value": "info"
          },
          {
            "count": 1,
            "value": "error"
          }
        ],
        "distinctValueCount": 2,
        "distinctValuesTruncated": false
      },
      {
        "key": "msg",
        "presentCount": 3,
        "presenceRatio": 1,
        "types": {
          "STRING": 3
        },
        "distinctValues": [],
        "distinctValueCount": 0,
        "distinctValuesTruncated": false
      },
      {
        "key": "duration_ms",
        "presentCount": 1,
        "presenceRatio": 0.333333,
        "types": {
          "NUMBER": 1
        },
        "distinctValues": [],
        "distinctValueCount": 0,
        "distinctValuesTruncated": false
      }
    ],
    "levels": {
      "TRACE": 0,
      "DEBUG": 0,
      "INFO": 2,
      "WARN": 0,
      "ERROR": 1,
      "FATAL": 0,
      "UNMAPPED": 0
    },
    "levelField": "level",
    "keysTruncated": false,
    "keyDiscoveryStoppedAtLine": null
  },
  "records": [],
  "errors": []
}
Tip
Two of three records carry duration_ms, so its presence ratio is 0.666667 at the fixed publication scale.

One unparseable line reported with its column

Inputjson
{
  "includeRecords": false,
  "logs": "{\"level\":\"info\"}\n{\"level\":}\n"
}
Expected outputjson
{
  "summary": {
    "lineCount": 2,
    "recordCount": 1,
    "blankLineCount": 0,
    "errorCount": 1,
    "errorsTruncated": false,
    "truncated": false,
    "sourceKind": "INLINE"
  },
  "stats": {
    "recordCount": 1,
    "fields": [
      {
        "key": "level",
        "presentCount": 1,
        "presenceRatio": 1,
        "types": {
          "STRING": 1
        },
        "distinctValues": [],
        "distinctValueCount": 0,
        "distinctValuesTruncated": false
      }
    ],
    "levels": {
      "TRACE": 0,
      "DEBUG": 0,
      "INFO": 1,
      "WARN": 0,
      "ERROR": 0,
      "FATAL": 0,
      "UNMAPPED": 0
    },
    "levelField": "level",
    "keysTruncated": false,
    "keyDiscoveryStoppedAtLine": null
  },
  "records": [],
  "errors": [
    {
      "code": "PARSE_ERROR",
      "line": 2,
      "column": 10
    }
  ]
}
Tip
The broken line is reported and the other line is still parsed, so a single bad producer does not cost you the whole batch.
  • Learn the shape of an unfamiliar JSON log stream before you write queries
  • Find which lines a producer emits as malformed JSON, and where

Avoid for

  • Reading logfmt text, which observability.parse_logfmt answers
  • Validating records against a schema, which schema.validate_ndjson answers

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

logsparsingjsonobservability