diff --git a/gren.json b/gren.json index 112a11d..e2b586a 100644 --- a/gren.json +++ b/gren.json @@ -11,11 +11,11 @@ "blaix/gren-ws4sql": "3.0.2", "gren-lang/core": "7.0.0", "gren-lang/node": "6.0.0", - "gren-lang/test": "5.0.0" + "gren-lang/test": "5.0.0", + "gren-lang/url": "6.0.0" }, "indirect": { - "gren-lang/test-runner-node": "7.0.0", - "gren-lang/url": "6.0.0" + "gren-lang/test-runner-node": "7.0.0" } } -} +} \ No newline at end of file diff --git a/src/Log.gren b/src/Log.gren index 619a923..48c66ee 100644 --- a/src/Log.gren +++ b/src/Log.gren @@ -1,8 +1,67 @@ module Log exposing ( Level(..) + , timestamp ) +import Time + type Level = Info String | Error String + + +{-| Convert a Time.Posix value to an ISO 8601 string in UTC. + Example output: "2026-04-06T14:30:00.000Z" +-} +timestamp : Time.Posix -> String +timestamp posix = + let + zone = Time.utc + year = Time.toYear zone posix + month = Time.toMonth zone posix |> monthToInt + day = Time.toDay zone posix + hour = Time.toHour zone posix + minute = Time.toMinute zone posix + second = Time.toSecond zone posix + millis = Time.toMillis zone posix + in + pad 4 year + ++ "-" + ++ pad 2 month + ++ "-" + ++ pad 2 day + ++ "T" + ++ pad 2 hour + ++ ":" + ++ pad 2 minute + ++ ":" + ++ pad 2 second + ++ "." + ++ pad 3 millis + ++ "Z" + + +-- Internal helpers + + +pad : Int -> Int -> String +pad width n = + String.padLeft width '0' (String.fromInt n) + + +monthToInt : Time.Month -> Int +monthToInt month = + when month is + Time.Jan -> 1 + Time.Feb -> 2 + Time.Mar -> 3 + Time.Apr -> 4 + Time.May -> 5 + Time.Jun -> 6 + Time.Jul -> 7 + Time.Aug -> 8 + Time.Sep -> 9 + Time.Oct -> 10 + Time.Nov -> 11 + Time.Dec -> 12 diff --git a/src/Main.gren b/src/Main.gren index 472fbd9..fcbbe2f 100644 --- a/src/Main.gren +++ b/src/Main.gren @@ -9,6 +9,7 @@ import HttpClient import HttpServer exposing (Request, ServerError(..), Method(..)) import HttpServer.Response as Response exposing (Response) import Init +import Log import Node exposing (Environment, Program) import Postmark import Registry.Db @@ -19,6 +20,8 @@ import Route.Session import Stream import Task exposing (Task) import Test.E2E.Helper as Helper +import Time +import Url import User exposing (User) @@ -161,7 +164,8 @@ update msg model = , command = response |> Route.initResponse - |> route model request + |> logRequest request + |> Task.andThen (route model request) |> Task.perform ResponseReady } @@ -175,6 +179,28 @@ update msg model = } } +logRequest : Request -> Route.Response -> Task Never Route.Response +logRequest request response = + let + method = + when request.method is + GET -> "GET" + HEAD -> "HEAD" + POST -> "POST" + PUT -> "PUT" + DELETE -> "DELETE" + CONNECT -> "CONNECT" + TRACE -> "TRACE" + PATCH -> "PATCH" + UNKNOWN str -> "UNKNOWN (" ++ str ++ ")" + + url = + method ++ " " ++ Url.toString request.url + in + Task.await Time.now <| \now -> + Task.succeed <| + Route.log (Log.Info (Log.timestamp now ++ " " ++ url)) response + route : Model -> Request -> Route.Response -> Task Never Route.Response route model request response = diff --git a/src/Route.gren b/src/Route.gren index e69a1b7..2ce57f0 100644 --- a/src/Route.gren +++ b/src/Route.gren @@ -84,10 +84,15 @@ respond { response = (Response res), stdout = stdout, stderr = stderr } = when level is Info string -> Stream.Log.line stdout string Error string -> Stream.Log.line stderr string + + sendLogs = + res.log + |> Array.map writeLog + |> Task.sequence + |> Task.execute in - res.log - |> Array.map writeLog - |> Array.map Task.execute - |> Array.pushLast (HttpResponse.send res.response) - |> Cmd.batch + Cmd.batch + [ sendLogs + , HttpResponse.send res.response + ]