UNPKG

24.5 kBMarkdownView Raw
1
2# loglevel [![NPM version][npm-image]][npm-url] [![NPM downloads](https://img.shields.io/npm/dw/loglevel.svg)](https://www.npmjs.com/package/loglevel) [![Build Status](https://github.com/pimterry/loglevel/actions/workflows/ci.yml/badge.svg)](https://github.com/pimterry/loglevel/actions/workflows/ci.yml)
3
4[npm-image]: https://img.shields.io/npm/v/loglevel.svg?style=flat
5[npm-url]: https://npmjs.org/package/loglevel
6
7> _Don't debug with logs alone - check out [HTTP Toolkit](https://httptoolkit.tech/javascript): beautiful, powerful & open-source tools for building, testing & debugging HTTP(S)_
8
9Minimal lightweight simple logging for JavaScript (browsers, node.js or elsewhere). loglevel extends console.log() & friends with level-based logging and filtering, with none of console's downsides.
10
11Test it out live in your browser console at https://pimterry.github.io/loglevel/demo/index.html
12
13Loglevel is a barebones reliable everyday logging library. It does not do fancy things, it does not let you reconfigure appenders or add complex log filtering rules or boil tea (more's the pity), but it does have the all core functionality that you actually use:
14
15## Features
16
17### Simple
18
19* Log things at a given level (trace/debug/info/warn/error) to the console object (as seen in all modern browsers & node.js)
20* Filter logging by level (all the above or 'silent'), so you can disable all but error logging in production, and then run log.setLevel("trace") in your console to turn it all back on for a furious debugging session
21* Single file, no dependencies, weighs in at 1.1KB minified and gzipped
22
23### Effective
24
25* Log methods gracefully fall back to simpler console logging methods if more specific ones aren't available: so calls to log.debug() go to console.debug() if possible, or console.log() if not
26* Logging calls still succeed even if there's no console object at all, so your site doesn't break when people visit with old browsers that don't support the console object (here's looking at you IE) and similar
27* This then comes together giving a consistent reliable API that works in every JavaScript environment with a console available, and never breaks anything anywhere else
28
29### Convenient
30
31* Log output keeps line numbers: most JS logging frameworks call console.log methods through wrapper functions, clobbering your stacktrace and making the extra info many browsers provide useless. We'll have none of that thanks.
32* It works with all the standard JavaScript loading systems out of the box (CommonJS, AMD, or just as a global)
33* Logging is filtered to "warn" level by default, to keep your live site clean in normal usage (or you can trivially re-enable everything with an initial log.enableAll() call)
34* Magically handles situations where console logging is not initially available (IE8/9), and automatically enables logging as soon as it does become available (when developer console is opened)
35* TypeScript type definitions included, so no need for extra `@types` packages
36* Extensible, to add other log redirection, filtering, or formatting functionality, while keeping all the above (except you will clobber your stacktrace, see Plugins below)
37
38## Downloading loglevel
39
40If you're using NPM, you can just run `npm install loglevel`.
41
42Alternatively, loglevel is also available via [Bower](https://github.com/bower/bower) (`bower install loglevel`), as a [Webjar](http://www.webjars.org/), or an [Atmosphere package](https://atmospherejs.com/spacejamio/loglevel) (for Meteor)
43
44Alternatively if you just want to grab the file yourself, you can download either the current stable [production version][min] or the [development version][max] directly, or reference it remotely on unpkg at [`https://unpkg.com/loglevel/dist/loglevel.min.js`][cdn] (this will redirect to a latest version, use the resulting redirected URL if you want to pin that version).
45
46Finally, if you want to tweak loglevel to your own needs or you immediately need the cutting-edge version, clone this repo and see [Developing & Contributing](#developing--contributing) below for build instructions.
47
48[min]: https://raw.github.com/pimterry/loglevel/master/dist/loglevel.min.js
49[max]: https://raw.github.com/pimterry/loglevel/master/dist/loglevel.js
50[cdn]: https://unpkg.com/loglevel/dist/loglevel.min.js
51
52## Setting it up
53
54loglevel supports AMD (e.g. RequireJS), CommonJS (e.g. Node.js) and direct usage (e.g. loading globally with a <script> tag) loading methods. You should be able to do nearly anything, and then skip to the next section anyway and have it work. Just in case though, here's some specific examples that definitely do the right thing:
55
56### CommonsJS (e.g. Node)
57
58```javascript
59var log = require('loglevel');
60log.warn("unreasonably simple");
61```
62
63### AMD (e.g. RequireJS)
64
65```javascript
66define(['loglevel'], function(log) {
67 log.warn("dangerously convenient");
68});
69```
70
71### Directly in your web page
72
73```html
74<script src="loglevel.min.js"></script>
75<script>
76log.warn("too easy");
77</script>
78```
79
80### As an ES6 module
81
82loglevel is written as a UMD module, with a single object exported. Unfortunately ES6 module loaders & transpilers don't all handle this the same way. Some will treat the object as the default export, while others use it as the root exported object. In addition, loglevel includes `default` property on the root object, designed to help handle this differences. Nonetheless, there's two possible syntaxes that might work for you:
83
84For most tools, using the default import is the most convenient and flexible option:
85
86```javascript
87import log from 'loglevel';
88log.warn("module-tastic");
89```
90
91For some tools though, it might better to wildcard import the whole object:
92
93```javascript
94import * as log from 'loglevel';
95log.warn("module-tastic");
96```
97
98There's no major difference, unless you're using TypeScript & building a loglevel plugin (in that case, see <https://github.com/pimterry/loglevel/issues/149>). In general though, just use whichever suits your environment, and everything should work out fine.
99
100### With noConflict()
101
102If you're using another JavaScript library that exposes a 'log' global, you can run into conflicts with loglevel. Similarly to jQuery, you can solve this by putting loglevel into no-conflict mode immediately after it is loaded onto the page. This resets to 'log' global to its value before loglevel was loaded (typically `undefined`), and returns the loglevel object, which you can then bind to another name yourself.
103
104For example:
105
106```html
107<script src="loglevel.min.js"></script>
108<script>
109var logging = log.noConflict();
110
111logging.warn("still pretty easy");
112</script>
113```
114
115### TypeScript
116
117loglevel includes its own type definitions, assuming you're using a modern module environment (e.g. Node.JS, webpack, etc), you should be able to use the ES6 syntax above, and everything will work immediately. If not, file a bug!
118
119If you really want to use LogLevel as a global however, but from TypeScript, you'll need to declare it as such first. To do that:
120
121* Create a `loglevel.d.ts` file
122* Ensure that file is included in your build (e.g. add it to `include` in your tsconfig, pass it on the command line, or use `///<reference path="./loglevel.d.ts" />`)
123* In that file, add:
124
125 ```typescript
126 import * as log from 'loglevel';
127 export as namespace log;
128 export = log;
129 ```
130
131## Documentation
132
133### Methods
134
135The loglevel API is extremely minimal. All methods are available on the root loglevel object, which it's suggested you name 'log' (this is the default if you import it in globally, and is what's set up in the above examples). The API consists of:
136
137#### Logging Methods
138
1395 actual logging methods, ordered and available as:
140
141* `log.trace(msg)`
142* `log.debug(msg)`
143* `log.info(msg)`
144* `log.warn(msg)`
145* `log.error(msg)`
146
147`log.log(msg)` is also available, as an alias for `log.debug(msg)`, to improve compatibility with `console`, and make migration easier.
148
149Exact output formatting of these will depend on the console available in the current context of your application. For example, many environments will include a full stack trace with all trace() calls, and icons or similar to highlight other calls.
150
151These methods should never fail in any environment, even if no console object is currently available, and should always fall back to an available log method even if the specific method called (e.g. warn) isn't available.
152
153Be aware that all this means that these method won't necessarily always produce exactly the output you expect in every environment; loglevel only guarantees that these methods will never explode on you, and that it will call the most relevant method it can find, with your argument. For example, `log.trace(msg)` in Firefox before version 64 prints the stacktrace by itself, and doesn't include your message (see [#84](https://github.com/pimterry/loglevel/issues/84)).
154
155#### `log.setLevel(level, [persist])`
156
157This disables all logging below the given level, so that after a `log.setLevel("warn")` call `log.warn("something")` or `log.error("something")` will output messages, but `log.info("something")` will not.
158
159This can take either a log level name or `'silent'` (which disables everything) in one of a few forms:
160
161* As a log level from the internal levels list, e.g. `log.levels.SILENT` ← _for type safety_
162* As a string, like `'error'` (case-insensitive) ← _for a reasonable practical balance_
163* As a numeric index from `0` (trace) to `5` (silent) ← _deliciously terse, and more easily programmable (...although, why?)_
164
165Where possible, the log level will be persisted. LocalStorage will be used if available, falling back to cookies if not. If neither is available in the current environment (i.e. in Node), or if you pass `false` as the optional 'persist' second argument, persistence will be skipped.
166
167If `log.setLevel()` is called when a console object is not available (in IE 8 or 9 before the developer tools have been opened, for example) logging will remain silent until the console becomes available, and then begin logging at the requested level.
168
169#### `log.setDefaultLevel(level)`
170
171This sets the current log level only if one has not been persisted and can’t be loaded. This is useful when initializing modules or scripts; if a developer or user has previously called `setLevel()`, this won’t alter their settings. For example, your application might set the log level to `error` in a production environment, but when debugging an issue, you might call `setLevel("trace")` on the console to see all the logs. If that `error` setting was set using `setDefaultLevel()`, it will still stay as `trace` on subsequent page loads and refreshes instead of resetting to `error`.
172
173The `level` argument takes is the same values that you might pass to `setLevel()`. Levels set using `setDefaultLevel()` never persist to subsequent page loads.
174
175#### `log.resetLevel()`
176
177This resets the current log level to the logger's default level (if no explicit default was set, then it resets it to the root logger's level, or to `WARN`) and clears the persisted level if one was previously persisted.
178
179#### `log.enableAll()` and `log.disableAll()`
180
181These enable or disable all log messages, and are equivalent to log.setLevel("trace") and log.setLevel("silent") respectively.
182
183#### `log.getLevel()`
184
185Returns the current logging level, as a number from 0 (trace) to 5 (silent)
186
187It's very unlikely you'll need to use this for normal application logging; it's provided partly to help plugin development, and partly to let you optimize logging code as below, where debug data is only generated if the level is set such that it'll actually be logged. This probably doesn't affect you, unless you've run profiling on your code and you have hard numbers telling you that your log data generation is a real performance problem.
188
189```javascript
190if (log.getLevel() <= log.levels.DEBUG) {
191 var logData = runExpensiveDataGeneration();
192 log.debug(logData);
193}
194```
195
196This notably isn't the right solution to avoid the cost of string concatenation in your logging. Firstly, it's very unlikely that string concatenation in your logging is really an important performance problem. Even if you do genuinely have hard metrics showing that it is though, the better solution that wrapping your log statements in this is to use multiple arguments, as below. The underlying console API will automatically concatenate these for you if logging is enabled, and if it isn't then all log methods are no-ops, and no concatenation will be done at all.
197
198```javascript
199// Prints 'My concatenated log message'
200log.debug("My ", "concatenated ", "log message");
201```
202
203#### `log.getLogger(loggerName)`
204
205This gets you a new logger object that works exactly like the root `log` object, but can have its level and logging methods set independently. All loggers must have a name (which is a non-empty string, or a [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)). Calling `getLogger()` multiple times with the same name will return an identical logger object.
206
207In large applications, it can be incredibly useful to turn logging on and off for particular modules as you are working with them. Using the `getLogger()` method lets you create a separate logger for each part of your application with its own logging level.
208
209Likewise, for small, independent modules, using a named logger instead of the default root logger allows developers using your module to selectively turn on deep, trace-level logging when trying to debug problems, while logging only errors or silencing logging altogether under normal circumstances.
210
211Example usage _(using CommonJS modules, but you could do the same with any module system):_
212
213```javascript
214// In module-one.js:
215var log = require("loglevel").getLogger("module-one");
216function doSomethingAmazing() {
217 log.debug("Amazing message from module one.");
218}
219
220// In module-two.js:
221var log = require("loglevel").getLogger("module-two");
222function doSomethingSpecial() {
223 log.debug("Special message from module two.");
224}
225
226// In your main application module:
227var log = require("loglevel");
228var moduleOne = require("module-one");
229var moduleTwo = require("module-two");
230log.getLogger("module-two").setLevel("TRACE");
231
232moduleOne.doSomethingAmazing();
233moduleTwo.doSomethingSpecial();
234// logs "Special message from module two."
235// (but nothing from module one.)
236```
237
238Loggers returned by `getLogger()` support all the same properties and methods as the default root logger, excepting `noConflict()` and the `getLogger()` method itself.
239
240Like the root logger, other loggers can have their logging level saved. If a logger’s level has not been saved, it will inherit the root logger’s level when it is first created. If the root logger’s level changes later, the new level will not affect other loggers that have already been created. Loggers with Symbol names (rather than string names) will be always considered as unique instances, and will never have their logging level saved or restored.
241
242Likewise, loggers will inherit the root logger’s `methodFactory`. After creation, each logger can have its `methodFactory` independently set. See the _plugins_ section below for more about `methodFactory`.
243
244#### `log.getLoggers()`
245
246This will return you the dictionary of all loggers created with `getLogger`, keyed off of their names.
247
248#### `log.rebuild()`
249
250Ensure the various logging methods (`log.info()`, `log.warn()`, etc.) behave as expected given the currently set logging level and `methodFactory`. It will also rebuild all child loggers of the logger this was called on.
251
252This is mostly useful for plugin development. When you call `log.setLevel()` or `log.setDefaultLevel()`, the logger is rebuilt automatically. However, if you change the logger’s `methodFactory`, you should use this to rebuild all the logging methods with your new factory.
253
254It is also useful if you change the level of the root logger and want it to affect child loggers that you’ve already created (and have not called `someChildLogger.setLevel()` or `someChildLogger.setDefaultLevel()` on). For example:
255
256```js
257var childLogger1 = log.getLogger("child1");
258childLogger1.getLevel(); // WARN (inherited from the root logger)
259
260var childLogger2 = log.getLogger("child2");
261childLogger2.setDefaultLevel("TRACE");
262childLogger2.getLevel(); // TRACE
263
264log.setLevel("ERROR");
265
266// At this point, the child loggers have not changed:
267childLogger1.getLevel(); // WARN
268childLogger2.getLevel(); // TRACE
269
270// To update them:
271log.rebuild();
272childLogger1.getLevel(); // ERROR (still inheriting from root logger)
273childLogger2.getLevel(); // TRACE (no longer inheriting because `.setDefaultLevel() was called`)
274```
275
276## Plugins
277
278### Existing plugins
279
280[loglevel-plugin-prefix](https://github.com/kutuluk/loglevel-plugin-prefix) - plugin for loglevel message prefixing.
281
282[loglevel-plugin-remote](https://github.com/kutuluk/loglevel-plugin-remote) - plugin for sending loglevel messages to a remote log server.
283
284ServerSend - <https://github.com/artemyarulin/loglevel-serverSend> - Forward your log messages to a remote server.
285
286DEBUG - <https://github.com/vectrlabs/loglevel-debug> - Control logging from a DEBUG environmental variable (similar to the classic [Debug](https://github.com/visionmedia/debug) module)
287
288### Writing plugins
289
290Loglevel provides a simple reliable minimal base for console logging that works everywhere. This means it doesn't include lots of fancy functionality that might be useful in some cases, such as log formatting and redirection (e.g. also sending log messages to a server over AJAX)
291
292Including that would increase the size and complexity of the library, but more importantly would remove stacktrace information. Currently log methods are either disabled, or enabled with directly bound versions of the console.log methods (where possible). This means your browser shows the log message as coming from your code at the call to `log.info("message!")` not from within loglevel, since it really calls the bound console method directly, without indirection. The indirection required to dynamically format, further filter, or redirect log messages would stop this.
293
294There's clearly enough enthusiasm for this even at that cost though that loglevel now includes a plugin API. To use it, redefine `log.methodFactory(methodName, logLevel, loggerName)` with a function of your own. This will be called for each enabled method each time the level is set (including initially), and should return a function to be used for the given log method `methodName`, at the given _configured_ (not actual) level `logLevel`, for a logger with the given name `loggerName`. If you'd like to retain all the reliability and features of loglevel, it's recommended that this wraps the initially provided value of `log.methodFactory`.
295
296For example, a plugin to prefix all log messages with "Newsflash: " would look like:
297
298```javascript
299var originalFactory = log.methodFactory;
300log.methodFactory = function (methodName, logLevel, loggerName) {
301 var rawMethod = originalFactory(methodName, logLevel, loggerName);
302
303 return function (message) {
304 rawMethod("Newsflash: " + message);
305 };
306};
307log.rebuild(); // Be sure to call the rebuild method in order to apply plugin.
308```
309
310*(The above supports only a single string `log.warn("...")` argument for clarity, but it's easy to extend to a [fuller variadic version](http://jsbin.com/xehoye/edit?html,console).)*
311
312If you develop and release a plugin, please get in contact! I'd be happy to reference it here for future users. Some consistency is helpful; naming your plugin 'loglevel-PLUGINNAME' (e.g. loglevel-newsflash) is preferred, as is giving it the 'loglevel-plugin' keyword in your package.json
313
314## Developing & Contributing
315
316In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.
317
318Builds can be run with npm: run `npm run dist` to build a distributable version of the project (in /dist), or `npm test` to just run the tests and linting. During development you can run `npm run watch` and it will monitor source files, and rerun the tests and linting as appropriate when they're changed.
319
320_Also, please don't manually edit files in the "dist" subdirectory as they are generated via Grunt. You'll find source code in the "lib" subdirectory!_
321
322#### Release process
323
324To do a release of loglevel:
325
326* Update the version number in package.json and bower.json
327* Run `npm run dist` to build a distributable version in dist/
328* Update the release history in this file (below)
329* Commit the built code, tagging it with the version number and a brief message about the release
330* Push to Github
331* Run `npm publish .` to publish to NPM
332
333## Release History
334
335v0.1.0 - First working release with apparent compatibility with everything tested
336
337v0.2.0 - Updated release with various tweaks and polish and real proper documentation attached
338
339v0.3.0 - Some bugfixes (#12, #14), cookie-based log level persistence, doc tweaks, support for Bower and JamJS
340
341v0.3.1 - Fixed incorrect text in release build banner, various other minor tweaks
342
343v0.4.0 - Use LocalStorage for level persistence if available, compatibility improvements for IE, improved error messages, multi-environment tests
344
345v0.5.0 - Fix for Modernizr+IE8 issues, improved setLevel error handling, support for auto-activation of desired logging when console eventually turns up in IE8
346
347v0.6.0 - Handle logging in Safari private browsing mode (#33), fix TRACE level persistence bug (#35), plus various minor tweaks
348
349v1.0.0 - Official stable release! Fixed a bug with localStorage in Android webviews, improved CommonJS detection, and added noConflict().
350
351v1.1.0 - Added support for including loglevel with preprocessing and .apply() (#50), and fixed QUnit dep version which made tests potentially unstable.
352
353v1.2.0 - New plugin API! Plus various bits of refactoring and tidy up, nicely simplifying things and trimming the size down.
354
355v1.3.0 - Make persistence optional in setLevel, plus lots of documentation updates and other small tweaks
356
357v1.3.1 - With the new optional persistence, stop unnecessarily persisting the initially set default level (warn)
358
359v1.4.0 - Add getLevel(), setDefaultLevel() and getLogger() functionality for more fine-grained log level control
360
361v1.4.1 - Reorder UMD (#92) to improve bundling tool compatibility
362
363v1.5.0 - Fix log.debug (#111) after V8 changes deprecating console.debug, check for `window` upfront (#104), and add `.log` alias for `.debug` (#64)
364
365v1.5.1 - Fix bug (#112) in level-persistence cookie fallback, which failed if it wasn't the first cookie present
366
367v1.6.0 - Add a name property to loggers and add log.getLoggers() (#114), and recommend unpkg as CDN instead of CDNJS.
368
369v1.6.1 - Various small documentation & test updates
370
371v1.6.2 - Include TypeScript type definitions in the package itself
372
373v1.6.3 - Avoid TypeScript type conflicts with other global `log` types (e.g. `core-js`)
374
375v1.6.4 - Ensure package.json's 'main' is a fully qualified path, to fix webpack issues
376
377v1.6.5 - Ensure the provided message is included when calling trace() in IE11
378
379v1.6.6 - Fix bugs in v1.6.5, which caused issues in node.js & IE < 9
380
381v1.6.7 - Fix a bug in environments with `window` defined but no `window.navigator`
382
383v1.6.8 - Update TypeScript type definitions to include `log.log()`.
384
385v1.7.0 - Add support for Symbol-named loggers, and a `.default` property to help with ES6 module usage.
386
387v1.7.1 - Update TypeScript types to support Symbol-named loggers.
388
389v1.8.0 - Add `resetLevel()` method to clear persisted levels & reset to defaults
390
391v1.8.1 - Fix incorrect type definitions for MethodFactory
392
393v1.9.0 - Added `rebuild()` method, overhaul dev & test setup, and fix some bugs (notably around cookies) en route
394
395v1.9.1 - Fix a bug introduced in 1.9.0 that broke `setLevel()` in some ESM-focused runtime environments
396
397## `loglevel` for enterprise
398
399Available as part of the Tidelift Subscription.
400
401The maintainers of `loglevel` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-loglevel?utm_source=npm-loglevel&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
402
403## License
404
405Copyright (c) 2013 Tim Perry
406Licensed under the MIT license.
407
\No newline at end of file