Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(log): allow to pass in custom loggers #69

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ declare function custom-router:use-beep-boop ($request as map(*), $response as m
Roaster transparently handles data from multipart/form-data requests to keep route handlers short and readable.
Please see the [file upload documentation](doc/file-upload.md) for more details on this.

## Logging

Roaster allows to pass in a fourth parameter to `roaster:route#4`.
It defaults to using util:log as before.

## Limitations

The library does not support yet support following OpenAPI feature(s):
Expand Down
19 changes: 16 additions & 3 deletions content/roaster.xqm
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,24 @@ declare function roaster:resolve-pointer ($config as map(*), $ref as xs:string*)
: 3. If two paths have the same (normalized) length, prioritize by appearance in API files, first one wins
:)
declare function roaster:route($api-files as xs:string+, $lookup as function(xs:string) as function(*)?) {
router:route($api-files, $lookup, auth:standard-authorization#2)
router:route($api-files, $lookup, auth:standard-authorization#2, util:log#2)
};

declare function roaster:route($api-files as xs:string+, $lookup as function(xs:string) as function(*)?, $middleware) {
router:route($api-files, $lookup, $middleware)
declare function roaster:route(
$api-files as xs:string+,
$lookup as function(xs:string) as function(*)?,
$middleware as (function(map(*), map(*)) as map(*)+)*
) {
router:route($api-files, $lookup, $middleware, util:log#2)
};

declare function roaster:route(
$api-files as xs:string+,
$lookup as function(xs:string) as function(*)?,
$middleware as (function(map(*), map(*)) as map(*)+)*,
$logger as function(xs:string, item()*) as empty-sequence()
) {
router:route($api-files, $lookup, $middleware, $logger)
};

declare function roaster:accepted-content-types () as xs:string* {
Expand Down
43 changes: 31 additions & 12 deletions content/router.xql
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ declare function router:resolve-pointer($config as map(*), $ref as xs:string*) {
: 2. use the matching route with the longest normalized pattern
: 3. If two paths have the same (normalized) length, prioritize by appearance in API files, first one wins
:)
declare function router:route ($api-files as xs:string+, $lookup as function(xs:string) as function(*)?, $middlewares as function(*)*) {
declare function router:route (
$api-files as xs:string+,
$lookup as function(xs:string) as function(*)?,
$middlewares as (function(map(*), map(*)) as map(*)+)*,
$logger as function(xs:string, item()*) as empty-sequence()
) {
let $controller := request:get-attribute("$exist:controller")
let $base-collection := ``[`{repo:get-root()}`/`{$controller}`/]``

Expand All @@ -88,7 +93,7 @@ declare function router:route ($api-files as xs:string+, $lookup as function(xs:
}

return (
util:log("debug", ``[[`{$request-data?id}`] request `{$request-data?method}` `{$request-data?path}`]``),
$logger("debug", ``[[`{$request-data?id}`] request `{$request-data?method}` `{$request-data?path}`]``),
try {
(: load router definitions :)
let $specs :=
Expand All @@ -114,12 +119,12 @@ declare function router:route ($api-files as xs:string+, $lookup as function(xs:
$matching-routes
else (
(: if there are multiple matches, prefer the one matching the longest pattern and the highest priority :)
util:log("debug", "ambigous route: " || $request-data?path),
$logger("debug", "ambigous route: " || $request-data?path),
head(sort($matching-routes, (), router:route-specificity#1))
)

return
router:process-request($first-match, $lookup, $middlewares)
router:process-request($first-match, $lookup, $middlewares, $logger)

} catch * {
let $error :=
Expand All @@ -142,7 +147,7 @@ declare function router:route ($api-files as xs:string+, $lookup as function(xs:
errors:get-status-code-from-error($err:code)

return
router:error($status-code, $error, $lookup)
router:error($status-code, $error, $lookup, $logger)
}
)
};
Expand Down Expand Up @@ -200,7 +205,12 @@ declare %private function router:route-specificity ($route as map(*)) as xs:inte
$route?priority (: sort ascending :)
};

declare %private function router:process-request ($pattern-map as map(*), $lookup as function(*), $custom-middlewares as function(*)*) {
declare %private function router:process-request (
$pattern-map as map(*),
$lookup as function(*),
$custom-middlewares as function(*)*,
$logger as function(xs:string, item()*) as empty-sequence()
) {
let $route :=
if (map:contains($pattern-map?config, $pattern-map?method)) then
$pattern-map?config?($pattern-map?method)
Expand All @@ -227,7 +237,7 @@ declare %private function router:process-request ($pattern-map as map(*), $looku

return (
router:write-response($status, $response, $route),
util:log("debug", ``[[`{$base-request?id}`] `{$base-request?method}` `{$base-request?path}`: `{$status}`]``)
$logger("debug", ``[[`{$base-request?id}`] `{$base-request?method}` `{$base-request?path}`: `{$status}`]``)
)
};

Expand Down Expand Up @@ -374,8 +384,13 @@ declare %private function router:error-description ($description as xs:string, $
: OAS configuration for the route and "_response" is the response data provided by the user function
: in the third argument of error().
:)
declare %private function router:error ($code as xs:integer, $error as map(*), $lookup as function(xs:string) as function(*)?) {
router:log-error($code, $error),
declare %private function router:error (
$code as xs:integer,
$error as map(*),
$lookup as function(xs:string) as function(*)?,
$logger as function(xs:string, item()*) as empty-sequence()
) {
router:log-error($code, $error, $logger),
(: unwrap error data :)
let $route := $error?_request?config
let $error := $error?_error
Expand Down Expand Up @@ -406,7 +421,7 @@ declare %private function router:error ($code as xs:integer, $error as map(*), $
"line": $err:line-number, "column": $err:column-number
}
return (
router:log-error(500, $_error),
router:log-error(500, $_error, $logger),
router:default-error-handler(500, $_error)
)
}
Expand Down Expand Up @@ -515,10 +530,14 @@ declare %private function router:is-rethrown-error($value as item()*) as xs:bool
map:contains($value, "_error")
};

declare %private function router:log-error ($code as xs:integer, $data as map(*)) as empty-sequence() {
declare %private function router:log-error (
$code as xs:integer,
$data as map(*),
$logger as function(xs:string, item()*) as empty-sequence()
) as empty-sequence() {
let $error := $data?_error => serialize(map{"method": "json"})
return
util:log("error",
$logger("error",
``[[`{$data?_request?id}`] `{$data?_request?method}` `{$data?_request?path}`: `{$code}`
`{$error}`]``)
};
12 changes: 11 additions & 1 deletion test/app/modules/custom-router.xq
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,14 @@ declare variable $custom-router:use := (
custom-router:use-beep-boop#2
);

roaster:route($custom-router:definitions, custom-router:lookup#1, $custom-router:use)
declare function custom-router:log-std ($level as xs:string, $message as item()*) as empty-sequence() {
switch(lower-case($level))
case 'error' return util:log-system-err($message)
default return util:log-system-out($message)
};

declare function custom-router:log-app ($level as xs:string, $message as item()*) as empty-sequence() {
util:log-app($level, "custom.log", $message)
};

roaster:route($custom-router:definitions, custom-router:lookup#1, $custom-router:use, custom-router:log-std#2)