infrastructure

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit d5884b7daeb4652b94ad48989b09a740bcddfe71
parent fe789ee72a77a5247e6e0019adfe9bb6ed125298
Author: Silas Brack <silasbrack@gmail.com>
Date:   Sun,  5 Jul 2026 18:08:49 +0200

refactor: simplify query-logs, keep SQL in DuckDB

Bash only generates the URL list (with HEAD checks to skip missing
files). All table definitions and SQL live in DuckDB init script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Mflake.nix | 71+++++++++++++++++++++++++++++------------------------------------------
1 file changed, 29 insertions(+), 42 deletions(-)

diff --git a/flake.nix b/flake.nix @@ -82,62 +82,49 @@ SINCE="''${1:-$(date -d '24 hours ago' +%Y-%m-%dT%H)}" UNTIL="''${2:-$(date +%Y-%m-%dT%H)}" - collect_urls() { - local dir=$1 ext=$2 urls="" current end path url + gen_urls() { + local dir=$1 ext=$2 urls="" current end url current=$(date -d "''${SINCE}:00:00" +%s) end=$(date -d "''${UNTIL}:00:00" +%s) while [ "$current" -le "$end" ]; do - path=$(date -d "@$current" +%Y/%m/%d/%H) - url="$BASE/$dir/$path.$ext" + url="$BASE/$dir/$(date -d @$current +%Y/%m/%d/%H).$ext" if ${pkgs.curl}/bin/curl -sf --head "$url" > /dev/null 2>&1; then - urls="$urls '$url'," + urls="$urls'$url'," fi current=$((current + 3600)) done - echo "''${urls%,}" + echo "[''${urls%,}]" } - echo "Scanning $SINCE → $UNTIL ..." - app_urls=$(collect_urls app json.gz) - nginx_urls=$(collect_urls nginx log.gz) + APP_URLS=$(gen_urls app json.gz) + NGINX_URLS=$(gen_urls nginx log.gz) - init="" - init="$init LOAD httpfs;" + ${pkgs.duckdb}/bin/duckdb -init <(cat <<DUCKDB + LOAD httpfs; - if [ -n "$app_urls" ]; then - init="$init CREATE TABLE app AS SELECT - to_timestamp(json_extract_string(j, '\$.__REALTIME_TIMESTAMP')::BIGINT / 1000000) as timestamp, - json_extract_string(j, '\$.MESSAGE') as message, - json_extract_string(j, '\$.PRIORITY') as priority, - json_extract_string(j, '\$.SYSLOG_IDENTIFIER') as identifier - FROM read_json_auto([$app_urls], format='newline_delimited', ignore_errors=true) j;" - echo " app: ready" - else - echo " app: no logs found" - fi + CREATE TABLE app AS + SELECT + to_timestamp(j."__REALTIME_TIMESTAMP"::BIGINT / 1000000) as timestamp, + j."MESSAGE" as message, + j."PRIORITY" as priority, + j."SYSLOG_IDENTIFIER" as identifier + FROM read_json($APP_URLS, format='newline_delimited', ignore_errors=true, + columns={__REALTIME_TIMESTAMP: 'VARCHAR', MESSAGE: 'VARCHAR', PRIORITY: 'VARCHAR', SYSLOG_IDENTIFIER: 'VARCHAR'}) j; - if [ -n "$nginx_urls" ]; then - init="$init CREATE TABLE nginx AS SELECT + CREATE TABLE nginx AS + SELECT regexp_extract(line, '^\S+', 0) as remote_addr, regexp_extract(line, '\[([^\]]+)\]', 1) as timestamp, - regexp_extract(line, '\"(\S+) (\S+) \S+\"', 1) as method, - regexp_extract(line, '\"(\S+) (\S+) \S+\"', 2) as path, - CAST(regexp_extract(line, '\" (\d+) ', 1) AS INTEGER) as status, - CAST(regexp_extract(line, '\" \d+ (\d+)', 1) AS INTEGER) as bytes, - regexp_extract(line, '\"([^\"]*)\"\s*\$', 1) as user_agent - FROM read_csv([$nginx_urls], header=false, columns={'line': 'VARCHAR'}, auto_detect=false, delim=E'\x01', quote=E'\x02', escape=E'\x02') t - WHERE line IS NOT NULL AND length(line) > 0;" - echo " nginx: ready" - else - echo " nginx: no logs found" - fi - - if [ -z "$app_urls" ] && [ -z "$nginx_urls" ]; then - echo "No logs found for the given range." - exit 0 - fi - - ${pkgs.duckdb}/bin/duckdb -init <(echo "$init") + regexp_extract(line, '"(\S+) (\S+) \S+"', 1) as method, + regexp_extract(line, '"(\S+) (\S+) \S+"', 2) as path, + CAST(regexp_extract(line, '" (\d+) ', 1) AS INTEGER) as status, + CAST(regexp_extract(line, '" \d+ (\d+)', 1) AS INTEGER) as bytes, + regexp_extract(line, '"([^"]*)"[^"]*\$', 1) as user_agent + FROM read_csv($NGINX_URLS, header=false, columns={'line': 'VARCHAR'}, auto_detect=false, + delim=chr(1), quote=chr(2), escape=chr(2)) t + WHERE line IS NOT NULL AND length(line) > 0; + DUCKDB + ) '' ; in