diff --git a/crates/nu-std/lib/log.nu b/crates/nu-std/lib/log.nu index 59c1204173..b35f2a33e8 100644 --- a/crates/nu-std/lib/log.nu +++ b/crates/nu-std/lib/log.nu @@ -1,24 +1,49 @@ -def CRITICAL_LEVEL [] { 50 } -def ERROR_LEVEL [] { 40 } -def WARNING_LEVEL [] { 30 } -def INFO_LEVEL [] { 20 } -def DEBUG_LEVEL [] { 10 } +export def "log CRITICAL_LEVEL" [] { 50 } +export def "log ERROR_LEVEL" [] { 40 } +export def "log WARNING_LEVEL" [] { 30 } +export def "log INFO_LEVEL" [] { 20 } +export def "log DEBUG_LEVEL" [] { 10 } + +export def "log CRITICAL_LEVEL_PREFIX" [] { "CRT" } +export def "log ERROR_LEVEL_PREFIX" [] { "ERR" } +export def "log WARNING_LEVEL_PREFIX" [] { "WRN" } +export def "log INFO_LEVEL_PREFIX" [] { "INF" } +export def "log DEBUG_LEVEL_PREFIX" [] { "DBG" } def parse-string-level [level: string] { ( - if $level == "CRITICAL" { (CRITICAL_LEVEL)} - else if $level == "CRIT" { (CRITICAL_LEVEL)} - else if $level == "ERROR" { (ERROR_LEVEL) } - else if $level == "WARNING" { (WARNING_LEVEL) } - else if $level == "WARN" { (WARNING_LEVEL) } - else if $level == "INFO" { (INFO_LEVEL) } - else if $level == "DEBUG" { (DEBUG_LEVEL) } - else { (INFO_LEVEL) } + if ($level in [(log CRITICAL_LEVEL_PREFIX) "CRIT" "CRITICAL"]) { + log CRITICAL_LEVEL + } else if ($level in [(log ERROR_LEVEL_PREFIX) "ERROR" ]) { + log ERROR_LEVEL + } else if ($level in [(log WARNING_LEVEL_PREFIX) "WARN" "WARNING"]) { + log WARNING_LEVEL + } else if ($level in [(log DEBUG_LEVEL_PREFIX) "DEBUG"]) { + log DEBUG_LEVEL + } else { + log INFO_LEVEL + } + ) +} + +def parse-int-level [level: int] { + ( + if ($level >= (log CRITICAL_LEVEL)) { + log CRITICAL_LEVEL_PREFIX + } else if ($level >= (log ERROR_LEVEL)) { + log ERROR_LEVEL_PREFIX + } else if ($level >= (log WARNING_LEVEL)) { + log WARNING_LEVEL_PREFIX + } else if ($level >= (log INFO_LEVEL)) { + log INFO_LEVEL_PREFIX + } else { + log DEBUG_LEVEL_PREFIX + } ) } def current-log-level [] { - let env_level = ($env | get -i NU_LOG_LEVEL | default (INFO_LEVEL)) + let env_level = ($env | get -i NU_LOG_LEVEL | default (log INFO_LEVEL)) try { ($env_level | into int) @@ -33,31 +58,50 @@ def now [] { # Log critical message export def "log critical" [message: string] { - if (current-log-level) > (CRITICAL_LEVEL) { return } + if (current-log-level) > (log CRITICAL_LEVEL) { return } - print --stderr $"(ansi red_bold)CRT|(now)|($message)(ansi reset)" + print --stderr $"(ansi red_bold)(log CRITICAL_LEVEL_PREFIX)|(now)|($message)(ansi reset)" } # Log error message export def "log error" [message: string] { - if (current-log-level) > (ERROR_LEVEL) { return } + if (current-log-level) > (log ERROR_LEVEL) { return } - print --stderr $"(ansi red)ERR|(now)|($message)(ansi reset)" + print --stderr $"(ansi red)(log ERROR_LEVEL_PREFIX)|(now)|($message)(ansi reset)" } # Log warning message export def "log warning" [message: string] { - if (current-log-level) > (WARNING_LEVEL) { return } + if (current-log-level) > (log WARNING_LEVEL) { return } - print --stderr $"(ansi yellow)WRN|(now)|($message)(ansi reset)" + print --stderr $"(ansi yellow)(log WARNING_LEVEL_PREFIX)|(now)|($message)(ansi reset)" } # Log info message export def "log info" [message: string] { - if (current-log-level) > (INFO_LEVEL) { return } + if (current-log-level) > (log INFO_LEVEL) { return } - print --stderr $"(ansi default)INF|(now)|($message)(ansi reset)" + print --stderr $"(ansi default)(log INFO_LEVEL_PREFIX)|(now)|($message)(ansi reset)" } # Log debug message export def "log debug" [message: string] { - if (current-log-level) > (DEBUG_LEVEL) { return } + if (current-log-level) > (log DEBUG_LEVEL) { return } - print --stderr $"(ansi default_dimmed)DBG|(now)|($message)(ansi reset)" + print --stderr $"(ansi default_dimmed)(log DEBUG_LEVEL_PREFIX)|(now)|($message)(ansi reset)" } + +# Log with custom message format and verbosity level +# +# Format reference: +# > %MSG% will be replaced by $message +# > %DATE% will be replaced by the timestamp of log in standard Nushell's log format: "%Y-%m-%dT%H:%M:%S%.3f" +# > %LEVEL% will be replaced by the standard Nushell's log verbosity prefixes, e.g. "CRT" +# +# Examples: +# > std log custom "my message" $"(ansi yellow)[%LEVEL%]MY MESSAGE: %MSG% [%DATE%](ansi reset)" (std log WARNING_LEVEL) +export def "log custom" [ + message: string, # Message inserted into the log template + format: string, # A string to be printed into stderr. + log_level: int # Log's verbosity level + ] { + if (current-log-level) > ($log_level) { return } + + print --stderr ($format | str replace "%MSG%" $message | str replace "%DATE%" (now) | str replace "%LEVEL%" (parse-int-level $log_level | into string)) +} \ No newline at end of file diff --git a/crates/nu-std/tests/test_logger.nu b/crates/nu-std/tests/test_logger.nu index ca6ee02d71..e3a8800cc3 100644 --- a/crates/nu-std/tests/test_logger.nu +++ b/crates/nu-std/tests/test_logger.nu @@ -36,3 +36,41 @@ export def test_debug [] { assert no message INFO debug assert message DEBUG debug DBG } + + +def "run custom" [system_level, format, message_level] { + do { + ^$nu.current-exe -c $'use std; NU_LOG_LEVEL=($system_level) std log custom "test message" "($format)" ($message_level)' + } | complete | get -i stderr +} + +def "assert custom message" [system_level, format, message_level] { + let output = (run custom $system_level $format $message_level) + assert equal ($output | str trim -r) ($format | str replace "%MSG%" "test message") +} + +def "assert custom message contains" [system_level, format, message_level, tested_str] { + let output = (run custom $system_level $format $message_level) + assert ($output | str contains $tested_str) + assert ($output | str contains "test message") +} + +def "assert custom message not contains" [system_level, format, message_level, tested_str] { + let output = (run custom $system_level $format $message_level) + assert (not ($output | str contains $tested_str)) + assert ($output | str contains "test message") +} + +def "assert no custom message" [system_level, format, message_level] { + let output = (run custom $system_level $format $message_level) + assert equal ($output | str trim -r) "" +} + +export def test_custom [] { + assert no custom message (log ERROR_LEVEL) "%MSG%" (log DEBUG_LEVEL) + assert custom message (log DEBUG_LEVEL) "%MSG%" (log INFO_LEVEL) + assert custom message (log WARNING_LEVEL) $"my_msg: %MSG%" (log CRITICAL_LEVEL) + + assert custom message contains (log DEBUG_LEVEL) $"(ansi yellow)[%LEVEL%]MY MESSAGE: %MSG% [%DATE%](ansi reset)" (log WARNING_LEVEL) (log WARNING_LEVEL_PREFIX) + assert custom message not contains (log DEBUG_LEVEL) $"(ansi yellow)MY MESSAGE: %MSG% [%DATE%](ansi reset)" (log WARNING_LEVEL) (log WARNING_LEVEL_PREFIX) +} \ No newline at end of file