improve service logs with json_fmt

This commit is contained in:
Ruben Fiszel
2024-08-31 23:01:17 +02:00
parent c62e152d27
commit c93ccb6f55
8 changed files with 78 additions and 12 deletions
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7)",
"query": "INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)",
"describe": {
"columns": [],
"parameters": {
@@ -11,10 +11,11 @@
"Timestamp",
"Varchar",
"Int8",
"Int8"
"Int8",
"Bool"
]
},
"nullable": []
},
"hash": "5c54f145e94dac117de02a94adf207684c52d8571b3507f4877c2cc151ff18b9"
"hash": "33c1793e55b1127d88d2509aadd0eb04e042463200f237b4c2cb176612fa16fe"
}
@@ -0,0 +1 @@
-- Add down migration script here
@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TABLE log_file ADD COLUMN IF NOT EXISTS json_fmt boolean DEFAULT false;
+3 -2
View File
@@ -42,6 +42,7 @@ use windmill_common::{
jobs::QueuedJob,
oauth2::REQUIRE_PREEXISTING_USER_FOR_OAUTH,
server::load_server_config,
tracing_init::JSON_FMT,
users::truncate_token,
utils::{now_from_db, rd_string, report_critical_error, Mode},
worker::{
@@ -500,8 +501,8 @@ async fn send_log_file_to_object_store(
let (ok_lines, err_lines) = read_log_counters(ts_str);
if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7)",
hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64)
if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)",
hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT)
.execute(db)
.await {
tracing::error!("Error inserting log file: {:?}", e);
+3
View File
@@ -8642,11 +8642,14 @@ paths:
type: integer
err_lines:
type: integer
json_fmt:
type: boolean
required:
- hostname
- mode
- log_ts
- file_path
- json_fmt
/service_logs/get_log_file/{path}:
get:
+2
View File
@@ -43,6 +43,7 @@ pub struct LogFile {
pub file_path: String,
pub ok_lines: Option<i64>,
pub err_lines: Option<i64>,
pub json_fmt: bool,
}
async fn list_files(
ApiAuthed { email, .. }: ApiAuthed,
@@ -62,6 +63,7 @@ async fn list_files(
"file_path",
"ok_lines",
"err_lines",
"json_fmt",
])
.order_by("log_ts", true)
.offset(offset)
+6 -4
View File
@@ -26,15 +26,16 @@ fn compact_layer<S>() -> Layer<S, format::DefaultFields, format::Format<format::
tracing_subscriber::fmt::layer().compact()
}
lazy_static::lazy_static! {
pub static ref JSON_FMT: bool = std::env::var("JSON_FMT").map(|x| x == "true").unwrap_or(false);
}
pub const LOGS_SERVICE: &str = "logs/services/";
pub const TMP_WINDMILL_LOGS_SERVICE: &str = concatcp!("/tmp/windmill/", LOGS_SERVICE);
pub fn initialize_tracing(hostname: &str) -> WorkerGuard {
let style = std::env::var("RUST_LOG_STYLE").unwrap_or_else(|_| "auto".into());
let json_fmt = std::env::var("JSON_FMT")
.map(|x| x == "true")
.unwrap_or(false);
if std::env::var("RUST_LOG").is_ok_and(|x| x == "debug" || x == "info") {
std::env::set_var(
@@ -71,13 +72,14 @@ pub fn initialize_tracing(hostname: &str) -> WorkerGuard {
ts_base.with(layer)
};
match json_fmt {
match *JSON_FMT {
true => ts_base
.with(
json_layer()
.with_writer(stdout_and_log_file_writer)
.flatten_event(true),
)
.with(CountingLayer::new())
.init(),
false => ts_base
.with(
@@ -9,6 +9,7 @@
import { sendUserToast } from '$lib/toast'
import { onDestroy } from 'svelte'
import { Loader2 } from 'lucide-svelte'
import { truncateRev } from '$lib/utils'
let minTs: undefined | string = undefined
let maxTs: undefined | string = undefined
@@ -29,6 +30,7 @@
file_path: string
ok_lines: number
err_lines: number
json_fmt: boolean
}
type ByHostname = Record<string, LogFile[]>
@@ -98,7 +100,8 @@
ts: ts,
file_path: log.file_path,
ok_lines: log.ok_lines ?? 1,
err_lines: log.err_lines ?? 0
err_lines: log.err_lines ?? 0,
json_fmt: log.json_fmt
})
if (
log.ok_lines != undefined &&
@@ -213,6 +216,50 @@
onDestroy(() => {
timeout && clearTimeout(timeout)
})
function processLogWithJsonFmt(log: string | undefined, jsonFmt: boolean): string {
if (!log) {
return ''
}
if (!jsonFmt) {
return log
}
try {
let res = ''
log.split('\n').forEach((line) => {
if (line.startsWith('{') && line.endsWith('}')) {
let obj = JSON.parse(line)
if (typeof obj == 'object') {
let nl = ''
if (obj['timestamp']) {
nl += obj['timestamp'] + ' '
}
if (obj['level']) {
nl += obj['level'] + ' '
}
if (obj['message']) {
nl += obj['message'] + ' '
}
delete obj['timestamp']
delete obj['level']
delete obj['message']
Object.keys(obj).forEach((key) => {
nl +=
key +
'=' +
(typeof obj[key] == 'object' ? JSON.stringify(obj[key]) : obj[key]) +
' '
})
res += nl + '\n'
}
}
})
return res
} catch (e) {
return log
}
}
</script>
<div class="w-full h-[70vh]" on:scroll|preventDefault>
@@ -346,7 +393,11 @@
scrollToBottom()
}}
>
<div class="text-sm pt-2 pl-0.5" style="width: 90px;">{hn}</div>
<div
class="text-sm pt-2 pl-0.5 whitespace-nowrap"
title={hn}
style="width: 90px;">{truncateRev(hn, 8)}</div
>
<div class="relative grow h-8 mr-2">
{#each files as file}
{@const okHeight = 100.0 * ((file.ok_lines * 1.0) / (max_lines ?? 1))}
@@ -421,7 +472,10 @@
noMaxH
isLoading={false}
tag={undefined}
content={logsContent[file.file_path].content}
content={processLogWithJsonFmt(
logsContent[file.file_path].content,
file.json_fmt
)}
/></div
>
{:else}