pipe-to-axiom.js2.8 KBView on GitHub #!/usr/bin/env node
// @ts-nocheck
/**
* Pipe console logs to Axiom
*
* This script intercepts stdout/stderr and sends logs to Axiom
* while also displaying them in the terminal.
*
* Usage: node scripts/pipe-to-axiom.js <dataset-name> <command...>
* Example: node scripts/pipe-to-axiom.js cedar-local-logs pnpm dev
*/
import { spawn } from 'child_process';
import { Axiom } from '@axiomhq/js';
const DATASET_NAME = process.argv[2];
const COMMAND_ARGS = process.argv.slice(3);
if (!DATASET_NAME || COMMAND_ARGS.length === 0) {
console.error('Usage: node scripts/pipe-to-axiom.js <dataset-name> <command...>');
console.error('Example: node scripts/pipe-to-axiom.js cedar-local-logs pnpm dev');
process.exit(1);
}
// Initialize Axiom client
const axiom = new Axiom({
token=[redacted] || '',
orgId: 'cedar-gcuj',
});
function pipeToAxiom(line) {
if (!line.trim()) return;
const event = {
message: line.trim(),
_time: new Date().toISOString(),
};
// fire-and-forget, non-blocking (batching API returns void)
try {
axiom.ingest(DATASET_NAME, [event]);
} catch {
// Silently fail - don't break the main process
}
}
// Join all command args to handle complex commands like "bash -c '...'"
const fullCommand = COMMAND_ARGS.join(' ');
// Buffer for incomplete lines
let stdoutBuffer = '';
let stderrBuffer = '';
// Spawn the process using shell to handle complex commands
const child = spawn(fullCommand, [], {
stdio: ['inherit', 'pipe', 'pipe'],
shell: true,
env: process.env, // Explicitly pass environment variables
});
// Helper to process buffered lines
function processLines(buffer, newData) {
const text = buffer + newData;
const lines = text.split('\n');
// Keep the last line in buffer if it doesn't end with newline
const completeLines = text.endsWith('\n') ? lines : lines.slice(0, -1);
const remainingBuffer = text.endsWith('\n') ? '' : lines[lines.length - 1];
// Send complete lines to Axiom
for (const line of completeLines) {
if (line.trim()) {
pipeToAxiom(line);
}
}
return remainingBuffer;
}
// Pipe stdout
child.stdout.on('data', (data) => {
const text = data.toString();
process.stdout.write(text); // Show in terminal
stdoutBuffer = processLines(stdoutBuffer, text);
});
// Pipe stderr
child.stderr.on('data', (data) => {
const text = data.toString();
process.stderr.write(text); // Show in terminal
stderrBuffer = processLines(stderrBuffer, text);
});
// Handle process exit
child.on('exit', (code) => {
// Send any remaining buffered lines
if (stdoutBuffer.trim()) {
pipeToAxiom(stdoutBuffer);
}
if (stderrBuffer.trim()) {
pipeToAxiom(stderrBuffer);
}
process.exit(code || 0);
});
child.on('error', (error) => {
console.error('Failed to start process:', error);
process.exit(1);
});