Log yang dihasilkan oleh runner CI/CD (seperti GitHub Actions, GitLab CI, atau Jenkins) sering kali mengandung ANSI escape codes mentah saat proses CLI memaksakan output berwarna. Ketika log mentah ini diteruskan ke sistem eksternal seperti Elasticsearch, viewer berbasis web, atau webhook alert Slack/Discord, karakter kontrol seperti \x1b[31m muncul sebagai teks sampah (garbled text) atau memicu kegagalan parsing format JSON.
Struktur ANSI Escape Sequence (CSI dan SGR)
Sebagian besar kode styling terminal menggunakan standar ECMA-48. Urutan ini diawali dengan karakter escape ASCII 0x1B (disingkat ESC), diikuti karakter kurung siku [. Kombinasi ESC [ disebut Control Sequence Introducer (CSI).
Format umum CSI adalah:
ESC [ <parameter> <karakter-perintah>Perintah paling umum dalam log build adalah Select Graphic Rendition (SGR) dengan karakter penutup m. Parameter di dalamnya berupa angka yang dipisahkan titik koma:
\x1b[0m: Reset semua atribut styling dan warna.\x1b[1m: Teks tebal (bold).\x1b[31m: Warna teks merah (standar 8-color).\x1b[38;5;196m: Warna teks mode 256-color (indeks 196).\x1b[38;2;255;0;0m: Warna teks Truecolor 24-bit (RGB: 255, 0, 0).
Selain SGR, CLI interaktif sering mengeluarkan perintah non-SGR seperti kursor bergerak (\x1b[2K untuk menghapus baris, \x1b[1A untuk naik satu baris) yang umumnya berasal dari progress bar build tool.
Metode 1: Stripping Menggunakan Regex
Untuk ingestion log ke database text-search atau webhook alert, menghapus (stripping) sequence secara instan adalah solusi paling ringan. Regex standar berikut menangani sebagian besar CSI sequence:
// Pattern regex untuk mencocokkan CSI sequence
const ansiRegex = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
function stripAnsi(text) {
return text.replace(ansiRegex, '');
}
// Contoh penggunaan:
const rawLog = "\x1b[32mSUCCESS:\x1b[0m Build passed in 12s";
console.log(stripAnsi(rawLog));
// Output: "SUCCESS: Build passed in 12s"Keterbatasan Regex: Pendekatan regex berbasis batch membutuhkan seluruh string buffer di memori. Regex tidak menangani pemulihan state jika sequence terpotong di batas chunk saat membaca stream log secara real-time.
Metode 2: Parsing dan Rendering HTML Menggunakan State Machine
Jika log perlu ditampilkan di dashboard web dengan warna aslinya, sequence harus diubah menjadi tag <span> dengan class CSS atau inline styling. Menggunakan state machine parser sederhana jauh lebih aman dari serangan Regular Expression Denial of Service (ReDoS) pada log berukuran besar.
Implementasi parser SGR minimal menggunakan TypeScript/JavaScript:
const COLOR_MAP: Record<string, string> = {
'31': 'color: #ef4444;', // Red
'32': 'color: #22c55e;', // Green
'33': 'color: #eab308;', // Yellow
'34': 'color: #3b82f6;', // Blue
};
function ansiToHtml(input: string): string {
// Escape HTML entities terlebih dahulu untuk mencegah XSS
const safeInput = input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
const regex = /\x1b\[([0-9;]*)m/g;
let html = '';
let lastIndex = 0;
let hasOpenSpan = false;
let match;
while ((match = regex.exec(safeInput)) !== null) {
html += safeInput.slice(lastIndex, match.index);
lastIndex = regex.lastIndex;
const code = match[1] || '0';
if (code === '0') {
if (hasOpenSpan) {
html += '</span>';
hasOpenSpan = false;
}
} else if (COLOR_MAP[code]) {
if (hasOpenSpan) {
html += '</span>';
}
html += `<span style="${COLOR_MAP[code]}">`;
hasOpenSpan = true;
}
}
html += safeInput.slice(lastIndex);
if (hasOpenSpan) {
html += '</span>';
}
return html;
}Mendeteksi Stream: Mengendalikan Output pada Level CI Pipeline
Cara terbaik memproses log ANSI adalah mencegah pembentukannya jika downstream consumer tidak membutuhkannya. Library CLI menentukan output ANSI berdasarkan kapabilitas TTY:
- Deteksi TTY: Command seperti
isatty(STDOUT_FILENO)di C atauprocess.stdout.isTTYdi Node.js memeriksa apakah output langsung tersambung ke terminal fisik. Di runner CI, stdout biasanya berupa pipe (non-TTY), sehingga library modern otomatis menonaktifkan warna. - Force Color Flags: Sebagian tool (misal: compiler compiler frontend atau test runner) mendeteksi CI environment via variabel
CI=truedan secara agresif menyalakan flag--color=always. - Standardisasi NO_COLOR: Standar de-facto lintas ekosistem software menyepakati bahwa adanya environment variable
NO_COLORharus mematikan output ANSI tanpa peduli deteksi TTY.
Tambahkan konfigurasi berikut pada job runner CI/CD untuk mematikan sequence pada sumbernya:
# Matikan formatting warna pada tingkat pipeline runner
env:
NO_COLOR: "1"
TERM: "dumb"Mengatur TERM=dumb memberitahu program CLI bahwa terminal target tidak memiliki kapabilitas rendering ANSI, sehingga CLI kembali ke plain-text streaming secara native.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!