81 lines
3.0 KiB
Plaintext
Executable File
81 lines
3.0 KiB
Plaintext
Executable File
# ===============================================================
|
||
# call_file — Timed JSON logger for Zsh config execution
|
||
# ===============================================================
|
||
# Source this file early (e.g. in ~/.zshenv). It defines a function:
|
||
# call_file /path/to/script.zsh [label]
|
||
# Logs NDJSON lines to $outfile (default: ~/zshrc-log.json)
|
||
|
||
function call_file() {
|
||
# No set -u here; be tolerant during early boot
|
||
local filepath="$1"
|
||
local label="${2:-}"
|
||
local resolved_path exit_code=0 duration_ms start_time end_time LOGFILE json_entry
|
||
|
||
[[ -z "$filepath" ]] && return 0
|
||
|
||
LOGFILE="${outfile:-$HOME/zshrc-log.json}"
|
||
: "${CALL_FILE_DEBUG:=0}"
|
||
|
||
# Resolve path (follow symlinks if present), fallback safely on macOS
|
||
if [[ -L "$filepath" ]]; then
|
||
if command -v readlink >/dev/null 2>&1 && readlink -f / >/dev/null 2>&1; then
|
||
resolved_path="$(readlink -f "$filepath" 2>/dev/null || echo "$filepath")"
|
||
elif command -v realpath >/dev/null 2>&1; then
|
||
resolved_path="$(realpath "$filepath" 2>/dev/null || echo "$filepath")"
|
||
else
|
||
resolved_path="$filepath"
|
||
fi
|
||
else
|
||
resolved_path="$filepath"
|
||
fi
|
||
|
||
# Derive label if not provided: config.zsh -> parent dir name, else file stem
|
||
if [[ -z "$label" ]]; then
|
||
local fname="${resolved_path:t}"
|
||
local dname="${resolved_path:h:t}"
|
||
if [[ "$fname" == "config.zsh" ]]; then
|
||
label="$dname"
|
||
else
|
||
label="${fname:r}"
|
||
fi
|
||
fi
|
||
|
||
# Guard if file missing
|
||
[[ ! -r "$resolved_path" ]] && {
|
||
print -u2 "call_file: missing or unreadable: $resolved_path"
|
||
return 1
|
||
}
|
||
|
||
# Timestamps (μs precision). Fall back if EPOCHREALTIME is unavailable.
|
||
start_time="${EPOCHREALTIME:-$(perl -MTime::HiRes=time -e 'printf "%.6f\n", time()')}"
|
||
[[ "$CALL_FILE_DEBUG" != "0" ]] && print -- "▶️ Starting $resolved_path (label: $label)"
|
||
|
||
{
|
||
# source quietly; the config can print if it wants—logs stay clean
|
||
source "$resolved_path"
|
||
} >/dev/null 2>&1 || exit_code=$?
|
||
|
||
end_time="${EPOCHREALTIME:-$(perl -MTime::HiRes=time -e 'printf "%.6f\n", time()')}"
|
||
# Floating math via awk to avoid zsh int math pitfalls
|
||
duration_ms=$(awk -v s="$start_time" -v e="$end_time" 'BEGIN {printf "%.5f", (e - s) * 1000}')
|
||
|
||
[[ "$CALL_FILE_DEBUG" != "0" ]] && print -- "⏱ Finished $resolved_path in ${duration_ms}ms (exit:${exit_code})"
|
||
|
||
# Ensure logfile dir exists
|
||
mkdir -p -- "$(dirname -- "$LOGFILE")" 2>/dev/null
|
||
|
||
# NDJSON entry (numbers are real numbers via --argjson)
|
||
json_entry=$(jq -nc \
|
||
--arg file "$resolved_path" \
|
||
--arg label "$label" \
|
||
--argjson start "$(printf "%.5f" "$start_time")" \
|
||
--argjson end "$(printf "%.5f" "$end_time")" \
|
||
--argjson duration "$(printf "%.5f" "$duration_ms")" \
|
||
--argjson code "$exit_code" \
|
||
'{file:$file, label:$label, start:$start, end:$end, duration_ms:$duration, exit_code:$code}')
|
||
|
||
# Append (don’t fail if file doesn’t exist yet)
|
||
if [[ -w "$LOGFILE" || ! -e "$LOGFILE" ]]; then
|
||
print -- "$json_entry" >>"$LOGFILE"
|
||
fi
|
||
} |