Added timestamps to project logging
This commit is contained in:
@@ -17,6 +17,7 @@ const REFRESHABLE_FILES: &[&str] = &[
|
|||||||
"monitor.sh",
|
"monitor.sh",
|
||||||
"monitor.bat",
|
"monitor.bat",
|
||||||
"_detect_port.ps1",
|
"_detect_port.ps1",
|
||||||
|
"_monitor_filter.ps1",
|
||||||
"test/run_tests.sh",
|
"test/run_tests.sh",
|
||||||
"test/run_tests.bat",
|
"test/run_tests.bat",
|
||||||
];
|
];
|
||||||
|
|||||||
18
templates/basic/_monitor_filter.ps1
Normal file
18
templates/basic/_monitor_filter.ps1
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$Port,
|
||||||
|
[Parameter(Mandatory=$true)][string]$Baud,
|
||||||
|
[switch]$Timestamps,
|
||||||
|
[string]$LogFile
|
||||||
|
)
|
||||||
|
|
||||||
|
arduino-cli monitor -p $Port -c "baudrate=$Baud" | ForEach-Object {
|
||||||
|
$line = $_
|
||||||
|
if ($Timestamps) {
|
||||||
|
$ts = Get-Date -Format "[HH:mm:ss.fff]"
|
||||||
|
$line = "$ts $line"
|
||||||
|
}
|
||||||
|
Write-Host $line
|
||||||
|
if ($LogFile) {
|
||||||
|
Add-Content -Path $LogFile -Value $line
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ setlocal enabledelayedexpansion
|
|||||||
:: monitor.bat -p COM3 Specify port
|
:: monitor.bat -p COM3 Specify port
|
||||||
:: monitor.bat -b 9600 Override baud rate
|
:: monitor.bat -b 9600 Override baud rate
|
||||||
:: monitor.bat --board mega Use baud from a named board
|
:: monitor.bat --board mega Use baud from a named board
|
||||||
|
:: monitor.bat --timestamps Prepend [HH:MM:SS.mmm] to each line
|
||||||
|
:: monitor.bat --log session.log Also write output to a file
|
||||||
|
|
||||||
set "SCRIPT_DIR=%~dp0"
|
set "SCRIPT_DIR=%~dp0"
|
||||||
set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
||||||
@@ -60,6 +62,8 @@ if "%BAUD%"=="" set "BAUD=115200"
|
|||||||
:: -- Parse arguments ------------------------------------------------------
|
:: -- Parse arguments ------------------------------------------------------
|
||||||
set "PORT="
|
set "PORT="
|
||||||
set "BOARD_NAME="
|
set "BOARD_NAME="
|
||||||
|
set "DO_TIMESTAMPS=0"
|
||||||
|
set "LOG_FILE="
|
||||||
|
|
||||||
:parse_args
|
:parse_args
|
||||||
if "%~1"=="" goto done_args
|
if "%~1"=="" goto done_args
|
||||||
@@ -68,6 +72,8 @@ if "%~1"=="--port" set "PORT=%~2" & shift & shift & goto parse_args
|
|||||||
if "%~1"=="-b" set "BAUD=%~2" & shift & shift & goto parse_args
|
if "%~1"=="-b" set "BAUD=%~2" & shift & shift & goto parse_args
|
||||||
if "%~1"=="--baud" set "BAUD=%~2" & shift & shift & goto parse_args
|
if "%~1"=="--baud" set "BAUD=%~2" & shift & shift & goto parse_args
|
||||||
if "%~1"=="--board" set "BOARD_NAME=%~2" & shift & shift & goto parse_args
|
if "%~1"=="--board" set "BOARD_NAME=%~2" & shift & shift & goto parse_args
|
||||||
|
if "%~1"=="--timestamps" set "DO_TIMESTAMPS=1" & shift & goto parse_args
|
||||||
|
if "%~1"=="--log" set "LOG_FILE=%~2" & shift & shift & goto parse_args
|
||||||
if "%~1"=="--help" goto show_help
|
if "%~1"=="--help" goto show_help
|
||||||
if "%~1"=="-h" goto show_help
|
if "%~1"=="-h" goto show_help
|
||||||
echo FAIL: Unknown option: %~1
|
echo FAIL: Unknown option: %~1
|
||||||
@@ -75,8 +81,11 @@ exit /b 1
|
|||||||
|
|
||||||
:show_help
|
:show_help
|
||||||
echo Usage: monitor.bat [-p PORT] [-b BAUD] [--board NAME]
|
echo Usage: monitor.bat [-p PORT] [-b BAUD] [--board NAME]
|
||||||
|
echo [--timestamps] [--log FILE]
|
||||||
echo Opens serial monitor. Baud rate from .anvil.toml.
|
echo Opens serial monitor. Baud rate from .anvil.toml.
|
||||||
echo --board NAME selects a board from [boards.NAME].
|
echo --board NAME selects a board from [boards.NAME].
|
||||||
|
echo --timestamps prepend [HH:MM:SS.mmm] to each line.
|
||||||
|
echo --log FILE also write output to a file.
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:done_args
|
:done_args
|
||||||
@@ -164,6 +173,27 @@ if "%PORT%"=="" (
|
|||||||
|
|
||||||
:: -- Monitor --------------------------------------------------------------
|
:: -- Monitor --------------------------------------------------------------
|
||||||
echo Opening serial monitor on %PORT% at %BAUD% baud...
|
echo Opening serial monitor on %PORT% at %BAUD% baud...
|
||||||
|
if "%DO_TIMESTAMPS%"=="1" echo Timestamps enabled.
|
||||||
|
if not "%LOG_FILE%"=="" echo Logging to: %LOG_FILE%
|
||||||
echo Press Ctrl+C to exit.
|
echo Press Ctrl+C to exit.
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
if "%DO_TIMESTAMPS%"=="1" if not "%LOG_FILE%"=="" goto monitor_ts_log
|
||||||
|
if "%DO_TIMESTAMPS%"=="1" goto monitor_ts
|
||||||
|
if not "%LOG_FILE%"=="" goto monitor_log
|
||||||
|
goto monitor_plain
|
||||||
|
|
||||||
|
:monitor_ts_log
|
||||||
|
powershell -NoProfile -File "%SCRIPT_DIR%\_monitor_filter.ps1" -Port "%PORT%" -Baud "%BAUD%" -Timestamps -LogFile "%LOG_FILE%"
|
||||||
|
goto :eof
|
||||||
|
|
||||||
|
:monitor_ts
|
||||||
|
powershell -NoProfile -File "%SCRIPT_DIR%\_monitor_filter.ps1" -Port "%PORT%" -Baud "%BAUD%" -Timestamps
|
||||||
|
goto :eof
|
||||||
|
|
||||||
|
:monitor_log
|
||||||
|
powershell -NoProfile -File "%SCRIPT_DIR%\_monitor_filter.ps1" -Port "%PORT%" -Baud "%BAUD%" -LogFile "%LOG_FILE%"
|
||||||
|
goto :eof
|
||||||
|
|
||||||
|
:monitor_plain
|
||||||
arduino-cli monitor -p %PORT% -c "baudrate=%BAUD%"
|
arduino-cli monitor -p %PORT% -c "baudrate=%BAUD%"
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
# ./monitor.sh -b 9600 Override baud rate
|
# ./monitor.sh -b 9600 Override baud rate
|
||||||
# ./monitor.sh --board mega Use baud from a named board
|
# ./monitor.sh --board mega Use baud from a named board
|
||||||
# ./monitor.sh --watch Reconnect after reset/replug
|
# ./monitor.sh --watch Reconnect after reset/replug
|
||||||
|
# ./monitor.sh --timestamps Prepend [HH:MM:SS.mmm] to each line
|
||||||
|
# ./monitor.sh --log session.log Also write output to a file
|
||||||
#
|
#
|
||||||
# Prerequisites: arduino-cli in PATH
|
# Prerequisites: arduino-cli in PATH
|
||||||
|
|
||||||
@@ -63,6 +65,8 @@ fi
|
|||||||
PORT=""
|
PORT=""
|
||||||
DO_WATCH=0
|
DO_WATCH=0
|
||||||
BOARD_NAME=""
|
BOARD_NAME=""
|
||||||
|
DO_TIMESTAMPS=0
|
||||||
|
LOG_FILE=""
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -70,10 +74,15 @@ while [[ $# -gt 0 ]]; do
|
|||||||
-b|--baud) BAUD="$2"; shift 2 ;;
|
-b|--baud) BAUD="$2"; shift 2 ;;
|
||||||
--board) BOARD_NAME="$2"; shift 2 ;;
|
--board) BOARD_NAME="$2"; shift 2 ;;
|
||||||
--watch) DO_WATCH=1; shift ;;
|
--watch) DO_WATCH=1; shift ;;
|
||||||
|
--timestamps) DO_TIMESTAMPS=1; shift ;;
|
||||||
|
--log) LOG_FILE="$2"; shift 2 ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
echo "Usage: ./monitor.sh [-p PORT] [-b BAUD] [--board NAME] [--watch]"
|
echo "Usage: ./monitor.sh [-p PORT] [-b BAUD] [--board NAME] [--watch]"
|
||||||
|
echo " [--timestamps] [--log FILE]"
|
||||||
echo " Opens serial monitor. Baud rate from .anvil.toml."
|
echo " Opens serial monitor. Baud rate from .anvil.toml."
|
||||||
echo " --board NAME selects a board from [boards.NAME]."
|
echo " --board NAME selects a board from [boards.NAME]."
|
||||||
|
echo " --timestamps prepend [HH:MM:SS.mmm] to each line."
|
||||||
|
echo " --log FILE also write output to a file."
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*) die "Unknown option: $1" ;;
|
*) die "Unknown option: $1" ;;
|
||||||
@@ -180,10 +189,33 @@ if [[ -z "$PORT" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# -- Output filter ---------------------------------------------------------
|
||||||
|
# Pipes stdin through optional timestamping and file logging.
|
||||||
|
monitor_filter() {
|
||||||
|
if [[ $DO_TIMESTAMPS -eq 1 ]] && [[ -n "$LOG_FILE" ]]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local ts
|
||||||
|
ts="[$(date '+%H:%M:%S.%3N')]"
|
||||||
|
printf "%s %s\n" "$ts" "$line"
|
||||||
|
printf "%s %s\n" "$ts" "$line" >> "$LOG_FILE"
|
||||||
|
done
|
||||||
|
elif [[ $DO_TIMESTAMPS -eq 1 ]]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
printf "[%s] %s\n" "$(date '+%H:%M:%S.%3N')" "$line"
|
||||||
|
done
|
||||||
|
elif [[ -n "$LOG_FILE" ]]; then
|
||||||
|
tee -a "$LOG_FILE"
|
||||||
|
else
|
||||||
|
cat
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# -- Watch mode ------------------------------------------------------------
|
# -- Watch mode ------------------------------------------------------------
|
||||||
if [[ $DO_WATCH -eq 1 ]]; then
|
if [[ $DO_WATCH -eq 1 ]]; then
|
||||||
echo "${CYN}${BLD}Persistent monitor on ${PORT} at ${BAUD} baud${RST}"
|
echo "${CYN}${BLD}Persistent monitor on ${PORT} at ${BAUD} baud${RST}"
|
||||||
echo "Reconnects after upload / reset / replug."
|
echo "Reconnects after upload / reset / replug."
|
||||||
|
[[ $DO_TIMESTAMPS -eq 1 ]] && echo "Timestamps enabled."
|
||||||
|
[[ -n "$LOG_FILE" ]] && echo "Logging to: $LOG_FILE"
|
||||||
echo "Press Ctrl+C to exit."
|
echo "Press Ctrl+C to exit."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -191,7 +223,8 @@ if [[ $DO_WATCH -eq 1 ]]; then
|
|||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
if [[ -e "$PORT" ]]; then
|
if [[ -e "$PORT" ]]; then
|
||||||
arduino-cli monitor -p "$PORT" -c "baudrate=$BAUD" 2>/dev/null || true
|
arduino-cli monitor -p "$PORT" -c "baudrate=$BAUD" 2>/dev/null \
|
||||||
|
| monitor_filter || true
|
||||||
echo "${YLW}--- ${PORT} disconnected ---${RST}"
|
echo "${YLW}--- ${PORT} disconnected ---${RST}"
|
||||||
else
|
else
|
||||||
echo "${CYN}--- Waiting for ${PORT} ...${RST}"
|
echo "${CYN}--- Waiting for ${PORT} ...${RST}"
|
||||||
@@ -205,7 +238,9 @@ if [[ $DO_WATCH -eq 1 ]]; then
|
|||||||
done
|
done
|
||||||
else
|
else
|
||||||
echo "Opening serial monitor on $PORT at $BAUD baud..."
|
echo "Opening serial monitor on $PORT at $BAUD baud..."
|
||||||
|
[[ $DO_TIMESTAMPS -eq 1 ]] && echo "Timestamps enabled."
|
||||||
|
[[ -n "$LOG_FILE" ]] && echo "Logging to: $LOG_FILE"
|
||||||
echo "Press Ctrl+C to exit."
|
echo "Press Ctrl+C to exit."
|
||||||
echo ""
|
echo ""
|
||||||
arduino-cli monitor -p "$PORT" -c "baudrate=$BAUD"
|
arduino-cli monitor -p "$PORT" -c "baudrate=$BAUD" | monitor_filter
|
||||||
fi
|
fi
|
||||||
@@ -831,6 +831,7 @@ fn test_full_project_structure() {
|
|||||||
"monitor.sh",
|
"monitor.sh",
|
||||||
"monitor.bat",
|
"monitor.bat",
|
||||||
"_detect_port.ps1",
|
"_detect_port.ps1",
|
||||||
|
"_monitor_filter.ps1",
|
||||||
"test/CMakeLists.txt",
|
"test/CMakeLists.txt",
|
||||||
"test/test_unit.cpp",
|
"test/test_unit.cpp",
|
||||||
"test/run_tests.sh",
|
"test/run_tests.sh",
|
||||||
@@ -1414,6 +1415,7 @@ fn test_refresh_freshly_extracted_is_up_to_date() {
|
|||||||
"upload.sh", "upload.bat",
|
"upload.sh", "upload.bat",
|
||||||
"monitor.sh", "monitor.bat",
|
"monitor.sh", "monitor.bat",
|
||||||
"_detect_port.ps1",
|
"_detect_port.ps1",
|
||||||
|
"_monitor_filter.ps1",
|
||||||
"test/run_tests.sh", "test/run_tests.bat",
|
"test/run_tests.sh", "test/run_tests.bat",
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1478,6 +1480,7 @@ fn test_refresh_does_not_list_user_files() {
|
|||||||
"upload.sh", "upload.bat",
|
"upload.sh", "upload.bat",
|
||||||
"monitor.sh", "monitor.bat",
|
"monitor.sh", "monitor.bat",
|
||||||
"_detect_port.ps1",
|
"_detect_port.ps1",
|
||||||
|
"_monitor_filter.ps1",
|
||||||
"test/run_tests.sh", "test/run_tests.bat",
|
"test/run_tests.sh", "test/run_tests.bat",
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1866,3 +1869,105 @@ fn test_script_errors_mention_toml_section_syntax() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Monitor: --timestamps and --log flags
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_monitor_scripts_accept_timestamps_flag() {
|
||||||
|
let tmp = TempDir::new().unwrap();
|
||||||
|
let ctx = TemplateContext {
|
||||||
|
project_name: "ts_test".to_string(),
|
||||||
|
anvil_version: "1.0.0".to_string(),
|
||||||
|
board_name: "uno".to_string(),
|
||||||
|
fqbn: "arduino:avr:uno".to_string(),
|
||||||
|
baud: 115200,
|
||||||
|
};
|
||||||
|
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
|
||||||
|
|
||||||
|
for script in &["monitor.sh", "monitor.bat"] {
|
||||||
|
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||||
|
assert!(
|
||||||
|
content.contains("--timestamps"),
|
||||||
|
"{} should accept --timestamps flag",
|
||||||
|
script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_monitor_scripts_accept_log_flag() {
|
||||||
|
let tmp = TempDir::new().unwrap();
|
||||||
|
let ctx = TemplateContext {
|
||||||
|
project_name: "log_test".to_string(),
|
||||||
|
anvil_version: "1.0.0".to_string(),
|
||||||
|
board_name: "uno".to_string(),
|
||||||
|
fqbn: "arduino:avr:uno".to_string(),
|
||||||
|
baud: 115200,
|
||||||
|
};
|
||||||
|
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
|
||||||
|
|
||||||
|
for script in &["monitor.sh", "monitor.bat"] {
|
||||||
|
let content = fs::read_to_string(tmp.path().join(script)).unwrap();
|
||||||
|
assert!(
|
||||||
|
content.contains("--log"),
|
||||||
|
"{} should accept --log flag for file output",
|
||||||
|
script
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_monitor_sh_has_timestamp_format() {
|
||||||
|
// The timestamp format should include hours, minutes, seconds, and millis
|
||||||
|
let tmp = TempDir::new().unwrap();
|
||||||
|
let ctx = TemplateContext {
|
||||||
|
project_name: "ts_fmt".to_string(),
|
||||||
|
anvil_version: "1.0.0".to_string(),
|
||||||
|
board_name: "uno".to_string(),
|
||||||
|
fqbn: "arduino:avr:uno".to_string(),
|
||||||
|
baud: 115200,
|
||||||
|
};
|
||||||
|
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
|
||||||
|
|
||||||
|
let content = fs::read_to_string(tmp.path().join("monitor.sh")).unwrap();
|
||||||
|
assert!(
|
||||||
|
content.contains("%H:%M:%S"),
|
||||||
|
"monitor.sh should use HH:MM:SS timestamp format"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
content.contains("%3N"),
|
||||||
|
"monitor.sh should include milliseconds in timestamps"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_monitor_sh_timestamps_work_in_watch_mode() {
|
||||||
|
// The timestamp filter should also apply in --watch mode
|
||||||
|
let tmp = TempDir::new().unwrap();
|
||||||
|
let ctx = TemplateContext {
|
||||||
|
project_name: "watch_ts".to_string(),
|
||||||
|
anvil_version: "1.0.0".to_string(),
|
||||||
|
board_name: "uno".to_string(),
|
||||||
|
fqbn: "arduino:avr:uno".to_string(),
|
||||||
|
baud: 115200,
|
||||||
|
};
|
||||||
|
TemplateManager::extract("basic", tmp.path(), &ctx).unwrap();
|
||||||
|
|
||||||
|
let content = fs::read_to_string(tmp.path().join("monitor.sh")).unwrap();
|
||||||
|
|
||||||
|
// The filter function should be called in the watch loop
|
||||||
|
assert!(
|
||||||
|
content.contains("monitor_filter"),
|
||||||
|
"monitor.sh should use a filter function for timestamps"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Count usages of monitor_filter - should appear in both watch and non-watch
|
||||||
|
let filter_count = content.matches("monitor_filter").count();
|
||||||
|
assert!(
|
||||||
|
filter_count >= 3,
|
||||||
|
"monitor_filter should be defined and used in both watch and normal mode (found {} refs)",
|
||||||
|
filter_count
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user