{"id":24860572,"url":"https://github.com/khuongduybui/fresh-logging","last_synced_at":"2025-10-15T06:30:43.108Z","repository":{"id":61251885,"uuid":"549351177","full_name":"khuongduybui/fresh-logging","owner":"khuongduybui","description":"Access Log middleware for Deno Fresh","archived":false,"fork":false,"pushed_at":"2023-12-15T08:40:16.000Z","size":79,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-16T23:07:58.942Z","etag":null,"topics":["deno","fresh","logging"],"latest_commit_sha":null,"homepage":"https://deno.land/x/fresh_logging","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/khuongduybui.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-10-11T03:49:36.000Z","updated_at":"2023-10-22T13:08:13.000Z","dependencies_parsed_at":"2023-12-05T09:46:47.446Z","dependency_job_id":null,"html_url":"https://github.com/khuongduybui/fresh-logging","commit_stats":{"total_commits":29,"total_committers":1,"mean_commits":29.0,"dds":0.0,"last_synced_commit":"d461ae81d22ed120aa5dd8a74afbbaa3769420d4"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khuongduybui%2Ffresh-logging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khuongduybui%2Ffresh-logging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khuongduybui%2Ffresh-logging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/khuongduybui%2Ffresh-logging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/khuongduybui","download_url":"https://codeload.github.com/khuongduybui/fresh-logging/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236582835,"owners_count":19172435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deno","fresh","logging"],"created_at":"2025-01-31T21:12:10.129Z","updated_at":"2025-10-15T06:30:37.825Z","avatar_url":"https://github.com/khuongduybui.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fresh-logging\n\n[Access Log](https://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format) [middleware](https://fresh.deno.dev/docs/concepts/middleware) for\n[Deno Fresh](https://fresh.deno.dev/).\n\n## Installation\n\nFirst of all, create [your fresh app](https://fresh.deno.dev/docs/getting-started/create-a-project).\n\nAdd logging to your `import_map.json`.\n\n```json\n{\n  \"imports\": {\n    \"$logging/\": \"https://deno.land/x/fresh_logging@1.1.2/\"\n  }\n}\n```\n\nConsume the logger in your app's `routes/_middleware.ts`.\n\n```ts\nimport * as getLogger from \"$logging/index.ts\";\n// or\n// import { getLogger, ... } from \"$logging/index.ts\";\n\nexport const handler = [\n  getLogger(),\n  // ... other middlewares\n];\n```\n\n**Note**: if `includeDuration` option is ON, `getLogger()` will also count the time taken by all of its subsequent middlewares. For example, putting\n`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\nwill yield the time taken only by the route handler.\n\n## Options\n\n`getLogger()` accepts an optional object `{}` with the following options:\n\n| Option            | Default Value                | Notes                                                                                                                                                   |\n| ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `format`          | `LoggingFormat.COMMON`       | The log format to use, defaulting to the [W3C Common Log Format](https://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format).             |\n| `utcTime`         | `false`                      | Whether to log timestamps in UTC or server timezone.                                                                                                    |\n| `includeDuration` | `false`                      | Whether to include handler response time.                                                                                                               |\n| `resolvers`       | `{}`                         | Selectively supply customer resolvers for the missing fields. See the next section on [limitations](#limitations) for more details.                     |\n| `logger`          | `console.info` +color -level | Optionally supply a custom logger function of type `(message: string) =\u003e string`. See the [logger section](#how-to-use-custom-logger) for more details. |\n| `combinedHeaders` | [\"Referer\", \"User-agent\"]    | Optionally supply custom request headers to include. Requires setting `format: LoggingFormat.APACHE_COMBINED`.                                          |\n\n## Limitations\n\nAs of v1.1.2, the following fields are **completely** omitted (hard-coded to `-`):\n\n- `rfc931` (client identifier): not sure how to obtain this\n- `authuser` (user identifier): not sure how to obtain this either\n- `bytes` (response content length): one way I can think of is to use `res.clone()` then read its as `ArrayBuffer` and get the `byteLength`, but that is both\n  time and memory consuming. Until I can find a more efficient way to obtain this piece of information, omission is the decision.\n\nUsers can use the `resolvers` to provide custom resolutions of the missing fields. For example, the following code snippet allows logging the response bytes:\n\n```ts\nimport { getLogger, ResolutionField } from \"$logging/index.ts\";\n\nexport const handler = [\n  getLogger({\n    resolvers: {\n      [ResolutionField.bytes]: async (_req, _ctx, res) =\u003e `${(await res.clone().arrayBuffer()).byteLength}`,\n    },\n  }),\n];\n```\n\nAgain, please note that the example above only serves to illustrate how to provide customer resolvers for the missing fields, the actual implementation is\nsub-optimal. Otherwise, it would have been included as default resolver for that field.\n\n## How to use custom logger\n\nSimply provide the `logger` option a function with the signature `(message: string) =\u003e string`, such as:\n\n```ts\nimport { getLogger } from \"$logging/index.ts\";\n\nexport const handler = [\n  getLogger({\n    logger: (message: string) =\u003e {\n      console.debug(message);\n      return message;\n    },\n  }),\n];\n```\n\nIn combination with a sophisticated logging solution such as https://github.com/onjara/optic, most logging use cases (console/stdout, rotating file, cloud,\netc.) can be implemented with relative ease.\n\n## Use [Apache Combined Log Format](https://httpd.apache.org/docs/2.4/logs.html#:~:text=%25B%20instead.-,Combined%20Log%20Format,-Another%20commonly%20used)\n\nSpecify `LoggingFormat.APACHE_COMBINED` for the `format` option like this:\n\n```ts\nimport { getLogger, LoggingFormat } from \"$logging/index.ts\";\n\nexport const handler = [\n  getLogger({\n    format: LoggingFormat.APACHE_COMBINED,\n  }),\n];\n```\n\nThe default two headers included are \"Referer\" and \"User-agent\". You can override that by optionally providing the `combinedHeaders` option, which expects a\nstring array of length 2.\n\n## A note about versioning\n\nFor 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\ninitial release of plugin, which supports Turnstile API v0.\n\nAll tags starting with `0.0.` are **mutable**. Expect breaking changes! Starting from `0.1.`, tags will be **immutable**. However, still expect breaking\nchanges. Starting from `1.`, semver will kick in and there will be no breaking changes until `2.`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhuongduybui%2Ffresh-logging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkhuongduybui%2Ffresh-logging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhuongduybui%2Ffresh-logging/lists"}