logshippers: add victorialogsend script

it's only very lightly tested but it seems to work.  the _stream
may be quite wrong, or perhaps that's a local admin decision anyway
This commit is contained in:
Daniel Barlow
2025-10-06 22:24:33 +01:00
parent 947a1c1373
commit af6e41db7a
2 changed files with 96 additions and 14 deletions

View File

@@ -11,6 +11,14 @@
}:
let
name = "logshippers";
luafy = name : source :
writeFennel name {
packages = [ anoia lualinux fennel ];
macros = [ anoia.dev ];
mainFunction = "run";
} source;
incz = luafy name ./incz.fnl;
victorialogsend = luafy name ./victorialogsend.fnl;
in
stdenv.mkDerivation {
inherit name;
@@ -21,22 +29,13 @@ stdenv.mkDerivation {
buildPhase = ''
fennelrepl --test ./incz.fnl
cp -p ${
writeFennel name {
packages = [
anoia
lualinux
fennel
];
macros = [
anoia.dev
];
mainFunction = "run";
} ./incz.fnl
} ${name}
fennelrepl --test ./victorialogsend.fnl
cp -p ${incz} incz
cp -p ${victorialogsend} victorialogsend
'';
installPhase = ''
install -D ${name} $out/bin/${name}
install -D incz $out/bin/incz
install -D victorialogsend $out/bin/victorialogsend
'';
}

View File

@@ -0,0 +1,83 @@
(local { : base64 : assoc } (require :anoia))
(local tai64 (require :anoia.tai64))
(local ll (require :lualinux))
(import-macros { : expect= : define-tests } :anoia.assert)
(local crlf "\r\n")
(fn chunk [str]
(let [len (# str)]
(string.format "%x%s%s%s" len crlf str crlf)))
(fn parse-url [str]
;; this is a very poor parser as it won't recognise
;; credentials in the authority and it lumps query-string/fragment
;; into the path
(let [(scheme host path)
(string.match str "(.-)://(.-)(/.+)")]
{ : scheme : host : path }))
(define-tests
(expect= (parse-url "https://www.example.com/stairway/to/heaven")
{ :scheme "https"
:host "www.example.com"
:path "/stairway/to/heaven"
}))
(fn parse-args [args]
(case args
["--basic-auth" auth & rest]
(assoc (parse-args rest) :auth auth)
[url] { :url (parse-url url) }
_ (error "invalid args")))
(fn http-header [host path auth]
(let [b64 (base64 :url)
authstr
(if auth
(string.format "Authorization: basic %s\n" (b64:encode auth))
"")]
(string.format
"POST %s HTTP/1.1\r
Host: %s\
%sTransfer-Encoding: chunked\r
\r
"
path host authstr)))
(fn format-timestamp-rfc3339 [timestamp prec]
(let [(sec nano) (-> timestamp tai64.from-timestamp tai64.to-utc)
subsec (string.sub (string.format "%09d" nano) 1 prec)]
(.. (os.date "!%FT%T" sec)
"." subsec
"Z")))
(define-tests
(expect= (format-timestamp-rfc3339 "@4000000068e2f0d3257dc09b" 9)
"2025-10-05T22:26:54.628998299Z"))
(fn process-line [line]
(let [(timestamp hostname service msg) (string.match line "(@%x+) (%g+) (%g+) (.+)$")]
(->
(string.format
"{%q:%q,%q:%q,%q:%q,%q:%q}\n"
:_time (format-timestamp-rfc3339 timestamp)
:service service
:_msg msg
:host hostname)
chunk)))
(fn run []
(let [{ : auth : url } (parse-args arg)]
(ll.write 1 (http-header url.host url.path auth))
(while (case (io.stdin:read "l")
line (ll.write 1 (process-line line))))
(ll.write 1 (chunk "")))
(io.stderr:write (ll.read 0)))
{ : run }