Access Log middleware for Deno Fresh.
First of all, create your fresh app.
Add logging to your import_map.json
.
{
"imports": {
"$logging/": "https://deno.land/x/[email protected]/"
}
}
Consume the logger in your app's routes/_middleware.ts
.
import * as getLogger from "$logging/index.ts";
// or
// import { getLogger, ... } from "$logging/index.ts";
export const handler = [
getLogger(),
// ... other middlewares
];
Note: if includeDuration
option is ON, getLogger()
will also count the time taken by all of its subsequent middlewares. For example, putting
getLogger()
at the beginning of your handler
array will count the time taken by all middlewares, while putting it at the very end of your handler
array
will yield the time taken only by the route handler.
getLogger()
accepts an optional object {}
with the following options:
Option | Default Value | Notes |
---|---|---|
format |
LoggingFormat.COMMON |
The log format to use, defaulting to the W3C Common Log Format. |
utcTime |
false |
Whether to log timestamps in UTC or server timezone. |
includeDuration |
false |
Whether to include handler response time. |
resolvers |
{} |
Selectively supply customer resolvers for the missing fields. See the next section on limitations for more details. |
logger |
console.info +color -level |
Optionally supply a custom logger function of type (message: string) => string . See the logger section for more details. |
combinedHeaders |
["Referer", "User-agent"] | Optionally supply custom request headers to include. Requires setting format: LoggingFormat.APACHE_COMBINED . |
As of v1.1.2, the following fields are completely omitted (hard-coded to -
):
rfc931
(client identifier): not sure how to obtain thisauthuser
(user identifier): not sure how to obtain this eitherbytes
(response content length): one way I can think of is to useres.clone()
then read its asArrayBuffer
and get thebyteLength
, but that is both time and memory consuming. Until I can find a more efficient way to obtain this piece of information, omission is the decision.
Users can use the resolvers
to provide custom resolutions of the missing fields. For example, the following code snippet allows logging the response bytes:
import { getLogger, ResolutionField } from "$logging/index.ts";
export const handler = [
getLogger({
resolvers: {
[ResolutionField.bytes]: async (_req, _ctx, res) => `${(await res.clone().arrayBuffer()).byteLength}`,
},
}),
];
Again, please note that the example above only serves to illustrate how to provide customer resolvers for the missing fields, the actual implementation is sub-optimal. Otherwise, it would have been included as default resolver for that field.
Simply provide the logger
option a function with the signature (message: string) => string
, such as:
import { getLogger } from "$logging/index.ts";
export const handler = [
getLogger({
logger: (message: string) => {
console.debug(message);
return message;
},
}),
];
In combination with a sophisticated logging solution such as https://github.com/onjara/optic, most logging use cases (console/stdout, rotating file, cloud, etc.) can be implemented with relative ease.
Specify LoggingFormat.APACHE_COMBINED
for the format
option like this:
import { getLogger, LoggingFormat } from "$logging/index.ts";
export const handler = [
getLogger({
format: LoggingFormat.APACHE_COMBINED,
}),
];
The default two headers included are "Referer" and "User-agent". You can override that by optionally providing the combinedHeaders
option, which expects a
string array of length 2.
For now, the versions are a.b.c-x.y.z
where a.b.c
is the plugin version and x.y.z
is the supported Turnstile API version. For example, 0.0.1-0
is the
initial release of plugin, which supports Turnstile API v0.
All tags starting with 0.0.
are mutable. Expect breaking changes! Starting from 0.1.
, tags will be immutable. However, still expect breaking
changes. Starting from 1.
, semver will kick in and there will be no breaking changes until 2.
.