{
  "slug": "log-merger",
  "name": "gizza-ai/log-merger",
  "version": "0.1.0",
  "title": "Log Merger — interleave multiple logs into one timeline — gizza.ai",
  "description": "Merge multiple log files into one timeline sorted by timestamp, with a [source] tag on every line. Free, private, runs in your browser — nothing uploaded.",
  "tags": [
    "log merger",
    "merge logs",
    "interleave logs",
    "combine log files",
    "unified timeline",
    "sort logs by timestamp",
    "log timeline"
  ],
  "category": "developer",
  "urls": {
    "page": "https://gizza.ai/tools/log-merger/",
    "markdown": "https://gizza.ai/tools/log-merger/index.md",
    "descriptor": "https://gizza.ai/tools/log-merger/tool.json",
    "deep_link_example": "https://gizza.ai/tools/log-merger/?logs=%23%20api.log%0A2024-06-01T10%3A00%3A02Z%20GET%20%2Fusers%20200%0A%23%20worker.log%0A2024-06-01T10%3A00%3A01Z%20job%20started&source_mode=header&order=asc&dedupe=true&align=true"
  },
  "cli": "gizza tool log-merger \"# api.log\n2024-06-01T10:00:02Z GET /users 200\n# worker.log\n2024-06-01T10:00:01Z job started\"",
  "tool": {
    "description": "Interleave multiple pasted log sources into one unified timeline, sorted by each line's parsed timestamp, with every line prefixed by a [source] tag. Sources inside the paste are delimited by header lines (`--- app.log ---`, `=== name ===`, GNU tail `==> name <==`, or markdown `# name`); set source_mode=blank to split on blank lines into source1, source2, … instead. Timestamps are auto-detected anywhere in a line (ISO 8601/RFC 3339, `YYYY-MM-DD HH:MM:SS`, syslog `Mon DD HH:MM:SS`, Apache `10/Oct/2000:13:55:36 -0700`, unix epoch seconds/ms); untimestamped lines inherit the previous line's timestamp so stack traces stay attached. order is asc (oldest first, default) or desc. dedupe drops repeated (timestamp, text) lines; align pads the [source] tags to a common width (default on). Runs locally.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "align": {
          "default": true,
          "description": "When true, pad each [source] tag to a common width so messages line up in a column.",
          "type": "boolean"
        },
        "dedupe": {
          "default": false,
          "description": "When true, drop later lines that repeat an already-emitted (timestamp, text) pair — useful for overlapping captures.",
          "type": "boolean"
        },
        "logs": {
          "description": "The concatenated log sources to interleave. Separate sources with header lines (`--- app.log ---`, `=== name ===`, GNU tail `==> name <==`, or markdown `# name`), or use source_mode=blank to split on blank lines.",
          "type": "string"
        },
        "order": {
          "default": "asc",
          "description": "Sort direction of the merged timeline: asc (oldest first) or desc (newest first).",
          "enum": [
            "asc",
            "desc"
          ],
          "type": "string"
        },
        "source_mode": {
          "default": "header",
          "description": "How sources are split: header (delimit by header lines like `--- app.log ---`) or blank (split on blank lines into source1, source2, …).",
          "enum": [
            "header",
            "blank"
          ],
          "type": "string"
        }
      },
      "required": [
        "logs"
      ],
      "type": "object"
    }
  }
}