Skip to content

Instantly share code, notes, and snippets.

@nemtsov
Created April 14, 2025 13:31

Revisions

  1. nemtsov created this gist Apr 14, 2025.
    92 changes: 92 additions & 0 deletions neo4j-query-to-json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,92 @@
    #!/usr/bin/env node

    const readline = require("readline");

    const outputAsTSV = process.argv.includes("--tsv");

    const fields = [
    "timestamp",
    "level",
    "tx_id",
    "duration",
    "planning",
    "waiting",
    "size",
    "session_type",
    "protocol",
    "driver_lib",
    "client_address",
    "server_address",
    "user",
    "client_ip",
    "uri",
    "db",
    "operation",
    "query",
    "params",
    "runtime",
    "error",
    "source_ip",
    "source_type",
    ];

    const logRegex =
    /^(?<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\+\d{4})\s+(?<level>\w+)\s+transaction id:(?<tx_id>-?\d+)\s+-\s+(?<duration>\d+)\s+ms: \(planning: (?<planning>\d+), waiting: (?<waiting>\d+)\)\s+-\s+(?<size>\d+)\s+B\s+-\s+(?<session_type>\S+)\s+(?<protocol>\S+)\s+(?:(?<driver_lib>[^\s/]+(?:\/[^\s/]+)?)\/(?<client_address>\d{1,3}(?:\.\d{1,3}){3}:\d+)\s+server\/(?<server_address>\d{1,3}(?:\.\d{1,3}){3}:\d+)>?\s+(?<user><[^>]*>)|(?<client_ip>\d{1,3}(?:\.\d{1,3}){3})\s+(?<uri>\S+)\s+(?<db>\S+))\s+-\s+(?<operation>\S+)\s+-\s+(?<query>[\s\S]*?)\s+-\s+(?<params>\{[\s\S]*?\})?\s+-\s+runtime=(?<runtime>\S+)\s+-\s+\{\}(?:\s+-\s+(?<error>[\s\S]*?))?(?=\n\d{4}-\d{2}-\d{2}|\n*$)$/gms;

    let buffer = "";

    const rl = readline.createInterface({
    input: process.stdin,
    terminal: false,
    });

    if (outputAsTSV) {
    process.stdout.write(fields.join("\t") + "\n");
    }

    rl.on("line", (line) => {
    buffer += line + "\n";

    if (!/ - \{\}(?:\s+-\s+.+)?\s*$/.test(line)) {
    return;
    }

    const matches = [...buffer.matchAll(logRegex)];

    for (const match of matches) {
    const g = match.groups;

    const parsed = {
    timestamp: g.timestamp,
    level: g.level,
    tx_id: Number(g.tx_id),
    duration: Number(g.duration),
    planning: Number(g.planning),
    waiting: Number(g.waiting),
    size: Number(g.size),
    session_type: g.session_type,
    protocol: g.protocol,
    driver_lib: g.driver_lib,
    client_address: g.client_address,
    server_address: g.server_address,
    user: g.user,
    client_ip: g.client_ip,
    uri: g.uri,
    db: g.db,
    operation: g.operation,
    query: g.query.replace(/\s+/g, " ").trim(),
    params: g.params ? g.params.trim() : null,
    runtime: g.runtime,
    error: g.error ? g.error.trim() : null,
    };

    if (outputAsTSV) {
    const row = fields.map((f) => parsed[f] ?? "").join("\t");
    process.stdout.write(row + "\n");
    } else {
    process.stdout.write(JSON.stringify(parsed) + "\n");
    }
    }

    buffer = "";
    });