{"id":27786333,"url":"https://github.com/clever/kayvee-js","last_synced_at":"2025-04-30T15:59:44.958Z","repository":{"id":21422063,"uuid":"24740168","full_name":"Clever/kayvee-js","owner":"Clever","description":"Package kayvee provides methods to output human and machine parseable strings","archived":false,"fork":false,"pushed_at":"2024-10-24T17:36:31.000Z","size":408,"stargazers_count":1,"open_issues_count":1,"forks_count":2,"subscribers_count":63,"default_branch":"master","last_synced_at":"2025-03-17T16:53:16.156Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Clever.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-02T23:10:04.000Z","updated_at":"2024-10-24T17:36:35.000Z","dependencies_parsed_at":"2024-10-24T20:07:34.761Z","dependency_job_id":"462562bb-6182-4159-ae16-99e5033d1c00","html_url":"https://github.com/Clever/kayvee-js","commit_stats":{"total_commits":221,"total_committers":31,"mean_commits":7.129032258064516,"dds":0.7285067873303168,"last_synced_commit":"5439be213ff6a843e389ec08ec2def7b16efb7c7"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Clever%2Fkayvee-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Clever%2Fkayvee-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Clever%2Fkayvee-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Clever%2Fkayvee-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Clever","download_url":"https://codeload.github.com/Clever/kayvee-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251737971,"owners_count":21635712,"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":[],"created_at":"2025-04-30T15:59:44.141Z","updated_at":"2025-04-30T15:59:44.944Z","avatar_url":"https://github.com/Clever.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"kayvee-js\n=========\n\nPackage kayvee provides methods to output human and machine parseable strings.\n\nRead the [Kayvee spec](https://github.com/Clever/kayvee) to learn more about the goals of Kayvee logging.\n\n## Example: kayvee/logger\n\nInitialization:\n\n```js\nvar kayvee = require(\"kayvee\");\n\nvar log = new kayvee.logger(\"logger-source\");\n```\n\nUse it to write metrics:\n\n```js\nlog.gauge(\"gauge-simple\", 18)\nlog.gaugeD(\"gauge-with-extra-data\", 3, {user_id: \"value\", scope: \"scope_system\"})\n```\nand structured logs:\n\n```js\nlog.infoD(\"non-metric-log\", {\"msg\": \"this is my info\", user: \"user-id\", group: \"group-id\"})\nlog.error(\"this is an error with no extra structured metadata\")\n```\n\n## Example: Kayvee Internals\n\nHere's are two examples snippets that log a kayvee formatted string:\n\n```js\nconsole.error(kayvee.format({\"hello\":\"world\"}));\n# {\"hello\":\"world\"}\n```\n\n```js\nconsole.error(kayvee.formatLog(\"test_source\", kayvee.INFO, \"title\", {\"foo\" : 1, \"bar\" : \"baz\"}));\n# {\"foo\":1,\"bar\":\"baz\",\"source\":\"test_source\",\"level\":\"info\",\"title\":\"title\"}\n```\n\n## Example: Kayvee Log Routing\n\nLog routing is a mechanism for defining where log lines should go once they've entered Clever's logging pipeline.   Routes are defined in a yaml file called kvconfig.yml.  Here's an example of a log routing rule that sends a slack message:\n\n```js\n// main.js\nconst kv = require(\"../kayvee-js\");\nkv.setGlobalRouting(\"./kvconfig.yml\");\n\nconst log = new kv.logger(\"myApp\");\n\nmodule.exports = (cb) =\u003e {\n    // Simple debugging\n    log.debug(\"Service has started\");\n\n    // Do something async\n    setImmediate(() =\u003e {\n        // Output structured data\n        log.infoD(\"DataResults\", {\"key\": \"value\"}); // Sends slack message\n\n        // You can use an object to send arbitrary key value pairs\n        log.infoD(\"DataResults\", {\"shorter\": \"line\"}); // will NOT send a slack message\n\n        cb(null);\n    });\n};\n```\n\n```yml\n# kvconfig.yml\nroutes:\n  key-val:\n    matchers:\n      title: [ \"DataResults\", \"QueryResults\" ]\n      key: [ \"value\" ]\n    output:\n      type: \"notifications\"\n      channel: \"#distribution\"\n      icon: \":rocket:\"\n      message: \"%{key}\"\n      user: \"Flight Tracker\"\n```\n\n### Testing\n\nTo ensure that your log-routing rules are correct, use `mockRouting` to temporarily mock out kayvee.  The mock kayvee will record which rules and how often they were matched.\n\n\n```js\n// main-test.js\nconst assert = require(\"assert\");\n\nconst kv = require(\"../kayvee-js\");\nkv.setGlobalRouting(\"./kvconfig.yml\");\n\nconst main = require(\"./main\");\n\nkv.mockRouting(kvdone =\u003e { // Don't nest kv.mockRouting calls!!\n    main(err =\u003e {\n        assert.ifError(err);\n\n        let ruleMatches = kvdone();\n        assert.equal(ruleMatches[\"key-val\"].length, 1);\n    });\n});\n```\n\nFor more information on log routing see https://clever.atlassian.net/wiki/spaces/ENG/pages/90570917/Application+Log+Routing\n\n## Testing\n\nRun `make test` to execute the tests\n\n## Change log\n\n- v3.3.0 - Middleware log lines are now routable\n- v3.2.0 - Exposed support for overriding the value field on metrics and alerts outputs\n- v3.1.0 - Added support for matching on booleans and a wildcard (\"*\")\n- v3.0.0 - Introduced log-routing\n- v2.4.0 - Add middleware.\n- v2.3.0 - Convert CoffeeScript to ES6 / Typescript.\n- v2.0.0 - Implement `logger` functionality along with support for `gauge` and `counter` metrics\n- v1.0.3 - Readme cleanup.\n- v1.0.2 - Prints stringified JSON, published as Javascript lib to NPM.\n- v0.0.1 - Initial release.\n\n## Usage\n\n### Logger\n\n#### kayvee/logger constructor\n\n```js\n# only source is required\nvar log = new kayvee.Logger(source, logLvl = process.env.KAYVEE_LOG_LEVEL, formatter = kv.format, output = console.error)\n```\n\nAn environment variable named `KAYVEE_LOG_LEVEL` can be used instead of setting `logLvl` in the application.\n\n#### kayvee/logger setConfig\n\n```js\nlog.setConfig(source, logLvl, formatter, output)\n```\n\nYou can also individually set the `config` using:\n\n* `setLogLevel`: defaults to `LOG_LEVELS.Debug`\n* `setFormatter`: defaults to `kv.format`\n* `setOutput`: defaults to `console.error`\n\n#### kayvee/logger logging\n\nTitles only:\n\n* `log.debug(\"title\")`\n* `log.info(\"title\")`\n* `log.warn(\"title\")`\n* `log.error(\"title\")`\n* `log.critical(\"title\")`\n\nTitle + Metadata:\n\n* `log.debugD(\"title\" {key1: \"value\", key2: \"val\"})`\n* `log.infoD(\"title\" {key1: \"value\", key2: \"val\"})`\n* `log.warnD(\"title\" {key1: \"value\", key2: \"val\"})`\n* `log.errorD(\"title\" {key1: \"value\", key2: \"val\"})`\n* `log.criticalD(\"title\" {key1: \"value\", key2: \"val\"})`\n\n#### kayvee/logger metrics\n\n* `log.counter(\"counter-name\")` defaults to value of `1`\n* `log.gauge(\"gauge-name\", 100)`\n\n* `log.counterD(\"counter-with-data\", 2, {extra: \"info\"})`\n* `log.gaugeD(\"gauge-with-data\", 2, {extra: \"info\"})`\n\n### Formatters\n\n#### format\n\n```js\nkayvee.format(data)\n```\nFormat converts a map to stringified json output\n\n#### formatLog\n\n```js\nkayvee.formatLog(source, level, title, data)\n```\n`formatLog` is similar to `format`, but takes additional reserved params to promote\nlogging best-practices\n\n- `source` (string) - locality of the log; an application name or part of an application\n- `level` (string) - available levels are\n    - \"unknown\n    - \"critical\n    - \"error\"\n    - \"warning\"\n    - \"info\"\n- `title` (string) - the event that occurred\n- `data` (object) - other parameters describing the event\n\n### Middleware\n\nKayvee includes logging middleware, compatible with expressJS.\n\nThe middleware can be added most simply via\n\n```js\nvar kayvee = require('kayvee');\n\nvar app = express();\napp.use(kayvee.middleware({\"source\":\"my-app\"}));\n```\n\nNote that `source` is a required field, since it clarifies which application is emitting the logs.\n\nThe middleware also supports further user configuration via the `options` object.\nIt prints the values of `headers` or the results of `handlers`.\nIf a value is `undefined`, the key will not be printed.\n\n- `headers`\n    - type: array of strings\n    - each of these strings is a request header, e.g. `X-Request-Id`\n- `handlers`\n    - type: an array of functions that return dicts of key-val pairs to be added to the logger's output.\n        These functions have the interface `(request, response) =\u003e { \"key\": \"val\" }`.\n- `ignore_dir`\n    - type: object containing the keys `directory` and `path`\n        - `directory` is the absolute file path of the directory that contains static files. This is the path passed to `express.static`\n        - `path` is the express mount point for these files. Defaults to `/`.\n        This will ignore all requests with `statusCode \u003c 400` to `path`/`file/path/in/dir`\n\nFor example, the below snippet causes the `X-Request-Id` request header and a param called `some_id` to be logged.\n\n\n```js\nvar kayvee = require('kayvee');\n\nvar app = express();\nvar options = {\n    source: \"my-app\",\n    headers: [\"x-request-id\"],\n    handlers: [\n        (req, res) =\u003e { return {\"some_id\": req.params.some_id}; }\n    ],\n};\napp.use(kayvee.middleware(options));\n```\n\nYou can also log with the request context using `req.log`. For example:\n\n```js\nmyRouteHandler(req, res) {\n    doTheThing((err, data) =\u003e {\n        if (err) {\n            req.log.errorD(\"do_the_thing_error\", {error: err.message});\n            res.send(500);\n        }\n        req.log.infoD(\"do_the_thing_success\", {response: data});\n        res.send(200);\n    });\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclever%2Fkayvee-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclever%2Fkayvee-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclever%2Fkayvee-js/lists"}