{"id":13446957,"url":"https://github.com/achojs/acho","last_synced_at":"2025-12-12T04:22:09.952Z","repository":{"id":28573195,"uuid":"32090977","full_name":"achojs/acho","owner":"achojs","description":"The Hackable Log","archived":false,"fork":false,"pushed_at":"2024-01-19T17:37:01.000Z","size":2241,"stargazers_count":190,"open_issues_count":1,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-10T08:01:39.083Z","etag":null,"topics":["debug","debugger","hackable","log","logger","logging","simple"],"latest_commit_sha":null,"homepage":"https://acho.js.org","language":"JavaScript","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/achojs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2015-03-12T17:25:12.000Z","updated_at":"2021-10-01T13:44:18.000Z","dependencies_parsed_at":"2024-06-18T14:40:37.887Z","dependency_job_id":"09f884f5-c4c2-4109-ac94-500c2e54937f","html_url":"https://github.com/achojs/acho","commit_stats":{"total_commits":303,"total_committers":10,"mean_commits":30.3,"dds":0.09570957095709576,"last_synced_commit":"f9227b3558db3469ad1ed51dbca7e826bf3fe52c"},"previous_names":["kikobeats/acho"],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achojs%2Facho","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achojs%2Facho/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achojs%2Facho/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/achojs%2Facho/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/achojs","download_url":"https://codeload.github.com/achojs/acho/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244837993,"owners_count":20518758,"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":["debug","debugger","hackable","log","logger","logging","simple"],"created_at":"2024-07-31T05:01:04.169Z","updated_at":"2025-10-22T19:47:23.076Z","avatar_url":"https://github.com/achojs.png","language":"JavaScript","readme":"# acho\n\n![Last version](https://img.shields.io/github/tag/achojs/acho.svg?style=flat-square)\n[![Build Status](https://img.shields.io/travis/achojs/acho/master.svg?style=flat-square)](https://travis-ci.org/achojs/acho)\n[![Coverage Status](https://img.shields.io/coveralls/achojs/acho.svg?style=flat-square)](https://coveralls.io/github/achojs/acho)\n[![Dependency status](https://img.shields.io/david/achojs/acho.svg?style=flat-square)](https://david-dm.org/achojs/acho)\n[![Dev Dependencies Status](https://img.shields.io/david/dev/achojs/acho.svg?style=flat-square)](https://david-dm.org/achojs/acho#info=devDependencies)\n[![NPM Status](https://img.shields.io/npm/dm/acho.svg?style=flat-square)](https://www.npmjs.org/package/acho)\n[![Donate](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square)](https://paypal.me/kikobeats)\n\n\u003e The \u0026#x3C;hackeable /\u0026#x3E; Log\n\n## Features\n\n* Different log levels skins.\n* Beauty object interpolation.\n* Diff \u0026 log trace support.\n* Easy to customize, easy to hack.\n\n## Install\n\n```bash\nnpm install acho\n```\n\n## Usage\n\n### Logging levels\n\n\u003cp\u003e\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eExamples\u003c/b\u003e\n    \u003c/summary\u003e\n  \u003cul\u003e\u003cli\u003e\u003ca href=\"./examples/levels.js\"\u003eDefaults\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"./examples/skin-cli.js\"\u003eSkin CLI\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"./examples/skin-syslog.js\"\u003eSkin Syslog\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\n\u003c/details\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/10.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\nThe first thing you need to do is create a new log instance:\n\n```js\nconst acho = require('acho')\nconst log = acho()\n```\n\nThen you can print a log based on the level:\n\n```js\nconst acho = require('acho')\nconst log = acho()\n\nacho.info('hello world')\n```\n\nAll methods are chainables:\n\n```js\nconst acho = require('acho')\nconst log = acho()\n\nacho\n  .info('hello world')\n  .error('something bad happens')\n```\n\nEstablishing the loglevel is a good way to filter out undesired information from output. The available levels by default are:\n\n- `fatal` : Display calls to `.fatal()` messages.\n- `error` : Display calls to `.fatal()`, `.error()` messages.\n- `warn`  : Display calls from `.fatal()`, `.error()`, `.warn()` messages.\n- `info`  : Display calls from `.fatal()`, `.error()`, `.warn()`, `info()` messages.\n- `debug` : Display calls from `.fatal()`, `.error()`, `.warn()`, `info()`, `debug()` messages.\n\nAdditionally exists two special levels:\n\n- `muted` :  Avoid all output.\n- `all`   : Allow print all message types.\n\nThe default log level is `all`. You can define it in the constructor:\n\n```js\nconst acho = require('acho')\nconst log = acho({ level: 'debug' })\n```\n\nor at runtime:\n\n```js\nlog.level = 'debug'\n```\n\n### Internal Store\n\nSometimes, when you are interacting with a logger you need to store the logs to be used later instead of print all of them.\n\nWe define `.push` as accumulator for store the log internally:\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/02.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n```js\nconst acho = require('acho')\nconst log = acho()\n\nlog.push('success', 'good job', 'well done', 'great!')\nconsole.log(log.messages.success)\n```\n\nIf you want to print previously stored messages, just call the method `.print`:\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/03.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\nor you can retrieve the logs programatically from the internal storage  at `acho.messages`\n\nThe method  `.add` combine `.push` and `.print` actions in one: It store the message internally but also print the log.\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/04.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n```js\nlog.add('info', 'this message is printed and stored')\nconsole.log(acho.messages.info)\n```\n\n### Formatters\n\n\u003cp\u003e\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eExamples\u003c/b\u003e\n    \u003c/summary\u003e\n  \u003cul\u003e\u003cli\u003e\u003ca href=\"./examples/interpolation.js\"\u003eInterpolation\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\n\u003c/details\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/09.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n\nWe use [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting. Below are the officially supported formatters:\n\n| Formatter | Representation                                                |\n|-----------|---------------------------------------------------------------|\n| `%s`      | String.                                                       |\n| `%d`      | Number (both integer and float).                              |\n| `%j`      | JSON serialization in one line                                |\n| `%J`      | JSON pretty object in multiple lines                          |\n| `%%`      | Single percent sign ('%'). This does not consume an argument. |\n\nBy default, the `%j` is applied when you pass an object to be logged:\n\n```js\nconst acho = require('acho')\nconst log = acho()\n\nlog.info({ hello: 'world', foo: 'bar' })\n// =\u003e 'info hello=world foo=bar'\n```\n\nIf you want to use a different formatter, use printf markup:\n\n```js\nconst acho = require('acho')\nconst log = acho()\n\nlog.info('formatting with object interpolation %J', {\n  hello: 'world',\n  foo: 'bar',\n  deep: {\n    foo: 'bar',\n    arr: [1, 2, 3, 4, 5]\n  }\n})\n```\n\n### Customization\n\n\u003cp\u003e\u003cdetails\u003e\n  \u003csummary\u003e\n    \u003cb\u003eExamples\u003c/b\u003e\n    \u003c/summary\u003e\n  \u003cul\u003e\u003cli\u003e\u003ca href=\"./examples/trace.js\"\u003eTrace \u0026 Diff\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"./examples/uppercase.js\"\u003eUppercase\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\n\u003c/details\u003e\u003c/p\u003e\n\nOne of the **acho** compromise is be easy to adapt. You can completely customize all the library functionalities.\n\nFor example, suppose you want to add a timestamp before your logs:\n\n\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/achojs/acho/master/docs/images/05.png\" alt=\"acho\"\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n```js\nconst acho = require('acho')\n\nconst log = acho({\n  // Customize how to print the 'type' of each message\n  outputType: type =\u003e `[${type}]`,\n\n  // Customize how to print the message.\n  // Add things before and/or after.\n  outputMessage: message =\u003e `${Date.now()} :: ${message}`\n})\n\nacho.info('I am hungry')\n```\n\nThat's all.\n\n## API\n\n### acho([options])\n\nIt creates a logger instance.\n\n#### options\n\n##### keyword\n\n![](https://raw.githubusercontent.com/achojs/acho/master/docs/images/07.png)\n\nType: `string`\u003c/br\u003e\nDefault: `loglevel`\n\nInstead of print the type log level, print the keyword. By default this behavior is not activated.\n\nYou can pass the special keyword `symbol` to show an unicode icon. This is special behavior for CLI programs.\n\n##### align\n\n![](https://raw.githubusercontent.com/achojs/acho/master/docs/images/08.png)\n\nType: `string`\u003c/br\u003e\nDefault: `' '`\n\nIt adds an alignment separator between the type of the message and the message.\n\nYou can provide your own separator or disable it providing a `false`.\n\n##### diff\n\n![](https://raw.githubusercontent.com/achojs/acho/master/docs/images/06.png)\n\nType: `boolean`\u003c/br\u003e\nDefault: `false`\n\nPrints trace between log from the same level. Specially useful to debug timings.\n\n##### upper\n\n![](https://raw.githubusercontent.com/achojs/acho/master/docs/images/12.png)\n\nType: `boolean`\u003c/br\u003e\nDefault: `false`.\n\nEnable or disable print log level in upper case.\n\n##### trace\n\n![](https://raw.githubusercontent.com/achojs/acho/master/docs/images/11.png)\n\nType: `boolean`|`number`\u003c/br\u003e\nDefault: `false`.\n\nPrints a numeric counter trace associated with each log line.\n\nThe value provided is the minimum quantity of time in milliseconds to consider print a different counter.\n\n##### offset\n\nType: `number`\u003c/br\u003e\nDefault: `2`.\n\nThe amount of left whitespace between the property key and all of it's sub-properties.\n\nThis option is only applied under JSON pretty object in multiple lines (%J).\n\n##### depth\n\nType: `number`\u003c/br\u003e\nDefault: `Infinity`.\n\nColapses all properties deeper than specified by depth.\n\nThis option is only applied under JSON pretty object in multiple lines (%J).\n\n##### level\n\nType: `string`\u003c/br\u003e\nDefault: `all`\n\nProvides the logging level. This sets from what level print logs using tranport.\n\nAdditionally you can provide `muted` to express don't print logs.\n\n##### transport\n\nType: `function`\u003c/br\u003e\nDefault: `console.log`\n\nDefines where write the log message.\n\n##### types\n\nType: `object`\n\nYou can provide the types and priorities.\n\n##### messages\n\nType: `object`\n\nIt provides a initial internal store state per each log level. This option is useful when you want to integrate the logger with the ouptut of a delayed function.\n\n##### print\n\nType: `function`\n\nProvides a function that determines how to print the messages. By default uses `.generateMessage` for generate the mesage that will be outputted.\n\n##### outputType\n\nType: `function`\n\nProvides a function to customize the type in the output.\n\n##### outputMessage\n\nType: `function`\n\nProvides a function to customize the message in the output.\n\n##### generateMessage\n\nType: `function`\n\nProvides a function that generate the message to be outputted. It combines other internal methods for generate the output (as `.isPrintable` or `.colorize`) and normally you are not interested in the definition of it, but you can provide it as option as well.\n\n##### generateTypeMessage\n\nType: `function`\n\nProvides a function used to generate the type message.\n\n### .push(\u0026lt;type\u0026gt;, \u0026lt;message\u0026gt;)\n\nStore a message of given `type` internally.\n\n#### type\n\nType: `string`\n\n#### message\n\nType: `string`\n\n### .add(\u0026lt;type\u0026gt;, \u0026lt;message\u0026gt;)\n\nStore a message of given `type` internally and also output it.\n\n#### type\n\nType: `string`\n\n#### message\n\nType: `string`\n\nFor each level you have a function following the pattern:\n\n### .print()\n\nPrints all messages internally stored.\n\n### .\\[loglevel\\](\u0026lt;message\u0026gt;)\n\nFor each log level that you declared in the constructor (or the default log levels provides by the library if you don't declare nothing) will be created a function with the same name to output a message with these log level.\n\n#### message\n\nType: `string`\n\n## License\n\n**acho** © [Kiko Beats](https://kikobeats.com), Released under the [MIT](https://github.com/achojs/acho/pulls/blob/master/LICENSE.md) License.\u003cbr\u003e\nAuthored and maintained by Kiko Beats with help from [contributors](https://github.com/achojs/acho/pulls/contributors).\n\n\u003e [kikobeats.com](https://kikobeats.com) · GitHub [Kiko Beats](https://github.com/kikobeats) · Twitter [@kikobeats](https://twitter.com/kikobeats)\n","funding_links":["https://paypal.me/kikobeats"],"categories":["JavaScript","others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachojs%2Facho","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fachojs%2Facho","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachojs%2Facho/lists"}