Files
ntfy-bridge/log.v
T
bruno 4e1d7cd94a Add config validation and dashboard
Add YAML config loading with validation, env overrides for secrets, and
a web dashboard exposing health, stats, and recent events.
2026-08-03 12:12:12 -04:00

120 lines
2.6 KiB
V
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module main
import time
pub enum LogLevel {
debug
info
warn
error
}
pub struct Logger {
level LogLevel
json_mode bool
}
pub fn new_logger(level LogLevel, json_mode bool) Logger {
return Logger{
level: level
json_mode: json_mode
}
}
fn level_string(level LogLevel) string {
return match level {
.debug { 'DEBUG' }
.info { 'INFO' }
.warn { 'WARN' }
.error { 'ERROR' }
}
}
fn level_icon(level LogLevel) string {
return match level {
.debug { '🔍' }
.info { 'ℹ️ ' }
.warn { '⚠️ ' }
.error { '❌' }
}
}
fn (l Logger) should_log(level LogLevel) bool {
return int(level) >= int(l.level)
}
pub fn (l Logger) log(level LogLevel, source string, event string, message string) {
if !l.should_log(level) {
return
}
if l.json_mode {
l.log_json(level, source, event, message)
} else {
l.log_human(level, source, event, message)
}
}
fn (l Logger) log_json(level LogLevel, source string, event string, message string) {
timestamp := time.now().format_rfc3339()
level_str := level_string(level)
// Manual JSON construction — simple enough to avoid importing json for each log line
// Escape backslashes and quotes in message
escaped := escape_json(message)
output := '{"timestamp":"${timestamp}","level":"${level_str}","source":"${source}","event":"${event}","message":"${escaped}"}'
if level == .error {
eprintln(output)
} else {
println(output)
}
}
fn escape_json(s string) string {
mut result := s.clone()
result = result.replace('\\', '\\\\')
result = result.replace('"', '\\"')
result = result.replace('\n', '\\n')
result = result.replace('\r', '\\r')
result = result.replace('\t', '\\t')
return result
}
fn (l Logger) log_human(level LogLevel, source string, _event string, message string) {
icon := level_icon(level)
ts := time.now()
ts_str := format_time_compact(ts)
output := '${ts_str} ${icon} [${source}] ${message}'
if level == .error {
eprintln(output)
} else if level == .warn {
eprintln(output)
} else {
println(output)
}
}
// format_time_compact returns "HH:MM:SS" (compact time for console output)
fn format_time_compact(t time.Time) string {
h := int(t.hour)
m := int(t.minute)
s := int(t.second)
return '${h:02d}:${m:02d}:${s:02d}'
}
pub fn (l Logger) debug(source string, event string, message string) {
l.log(.debug, source, event, message)
}
pub fn (l Logger) info(source string, event string, message string) {
l.log(.info, source, event, message)
}
pub fn (l Logger) warn(source string, event string, message string) {
l.log(.warn, source, event, message)
}
pub fn (l Logger) error(source string, event string, message string) {
l.log(.error, source, event, message)
}