Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2: First steps, drop old IE support, fix debug #203

Merged
merged 9 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
pull_request: {}
push:
branches:
- master
- main
# Allow manual runs if needed.
workflow_dispatch: {}

Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ If you'd like to file a bug or a feature request for loglevel, the best option i

If you're filing a feature request, please remember:

* Feature requests significantly expanding the scope of loglevel outside the description in [the readme](https://github.com/pimterry/loglevel/blob/master/README.md) will probably be rejected.
* Feature requests significantly expanding the scope of loglevel outside the description in [the readme](https://github.com/pimterry/loglevel/blob/main/README.md) will probably be rejected.
* Features that can't be meaningfully implemented in a cross-environment compatible manner won't be implemented.
* Please check the previously opened issues to see if somebody else has suggested it first.
* Consider submitting a pull request to add the feature instead, if you're confident it fits within the above.
Expand Down Expand Up @@ -60,12 +60,12 @@ How to make your change and submit it
1. Ensure you have Node.js v14 or later (some tests can run on earlier versions, but the full suite requires this version).
2. Fork loglevel.
3. Clone your fork locally.
4. Create a branch from `master` for your change.
4. Create a branch from `main` for your change.
5. Write some tests in `test/` for your change, as relevant.
6. Make your code changes in `lib/loglevel.js`.
7. Check your code all passes (run `npm test`). If you have issues and need to debug the tests, see the details on ["running tests"](#running-tests) below.
8. Commit your changes.
9. Open a pull request back to `master` in loglevel.
9. Open a pull request back to `main` in loglevel.

Running Tests
-------------
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
[npm-image]: https://img.shields.io/npm/v/loglevel.svg?style=flat
[npm-url]: https://npmjs.org/package/loglevel

⚠️ **You are looking at an in-development branch for Loglevel 2.0!** There will be a lot of breaking changes here. For release versions of Loglevel, check out the [`main` branch](https://github.com/pimterry/loglevel/tree/main).

> _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)_

Minimal 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.
Expand Down Expand Up @@ -45,8 +47,8 @@ Alternatively if you just want to grab the file yourself, you can download eithe

Finally, 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.

[min]: https://raw.github.com/pimterry/loglevel/master/dist/loglevel.min.js
[max]: https://raw.github.com/pimterry/loglevel/master/dist/loglevel.js
[min]: https://raw.github.com/pimterry/loglevel/main/dist/loglevel.min.js
[max]: https://raw.github.com/pimterry/loglevel/main/dist/loglevel.js
[cdn]: https://unpkg.com/loglevel/dist/loglevel.min.js

## Setting it up
Expand Down Expand Up @@ -396,6 +398,10 @@ v1.9.1 - Fix a bug introduced in 1.9.0 that broke `setLevel()` in some ESM-focus

v1.9.2 - Remove unnecessarily extra test & CI files from deployed package

v2.0.0 **(In development)**
- Removed support for Internet Explorer v10 and older.
- Calling `debug(msg)` shows up as an actual “debug” level message in browser consoles (in v1, it showed up as “log” or “info” depending on your browser).

## `loglevel` for enterprise

Available as part of the Tidelift Subscription.
Expand Down
66 changes: 4 additions & 62 deletions dist/loglevel.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
// Slightly dubious tricks to cut down minimized file size
var noop = function() {};
var undefinedType = "undefined";
var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
/Trident\/|MSIE /.test(window.navigator.userAgent)
);

var logMethods = [
"trace",
Expand All @@ -29,51 +26,15 @@
var _loggersByName = {};
var defaultLogger = null;

// Cross-browser bind equivalent that works at least back to IE6
function bindMethod(obj, methodName) {
var method = obj[methodName];
if (typeof method.bind === 'function') {
return method.bind(obj);
} else {
try {
return Function.prototype.bind.call(method, obj);
} catch (e) {
// Missing bind shim or IE8 + Modernizr, fallback to wrapping
return function() {
return Function.prototype.apply.apply(method, [obj, arguments]);
};
}
}
}

// Trace() doesn't print the message in IE, so for that case we need to wrap it
function traceForIE() {
if (console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
// In old IE, native console methods themselves don't have apply().
Function.prototype.apply.apply(console.log, [console, arguments]);
}
}
if (console.trace) console.trace();
}

// Build the best logging method possible for this env
// Wherever possible we want to bind, not wrap, to preserve stack traces
function realMethod(methodName) {
if (methodName === 'debug') {
methodName = 'log';
}

function defaultMethodFactory(methodName, _level, _loggerName) {
if (typeof console === undefinedType) {
return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
} else if (methodName === 'trace' && isIE) {
return traceForIE;
return noop;
} else if (console[methodName] !== undefined) {
return bindMethod(console, methodName);
return console[methodName].bind(console);
} else if (console.log !== undefined) {
return bindMethod(console, 'log');
return console.log.bind(console);
} else {
return noop;
}
Expand Down Expand Up @@ -102,25 +63,6 @@
}
}

// In old IE versions, the console isn't present until you first open it.
// We build realMethod() replacements here that regenerate logging methods
function enableLoggingWhenConsoleArrives(methodName) {
return function () {
if (typeof console !== undefinedType) {
replaceLoggingMethods.call(this);
this[methodName].apply(this, arguments);
}
};
}

// By default, we use closely bound real methods wherever possible, and
// otherwise we wait for a console to appear, and then try again.
function defaultMethodFactory(methodName, _level, _loggerName) {
/*jshint validthis:true */
return realMethod(methodName) ||
enableLoggingWhenConsoleArrives.apply(this, arguments);
}

function Logger(name, factory) {
// Private instance variables.
var self = this;
Expand Down
2 changes: 1 addition & 1 deletion dist/loglevel.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 7 additions & 66 deletions lib/loglevel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
// Slightly dubious tricks to cut down minimized file size
var noop = function() {};
var undefinedType = "undefined";
var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
/Trident\/|MSIE /.test(window.navigator.userAgent)
);

var logMethods = [
"trace",
Expand All @@ -34,54 +31,17 @@
var _loggersByName = {};
var defaultLogger = null;

// Cross-browser bind equivalent that works at least back to IE6
function bindMethod(obj, methodName) {
var method = obj[methodName];
if (typeof method.bind === 'function') {
return method.bind(obj);
} else {
try {
return Function.prototype.bind.call(method, obj);
} catch (e) {
// Missing bind shim or IE8 + Modernizr, fallback to wrapping
return function() {
return Function.prototype.apply.apply(method, [obj, arguments]);
};
}
}
}

// Trace() doesn't print the message in IE, so for that case we need to wrap it
function traceForIE() {
if (console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
// In old IE, native console methods themselves don't have apply().
Function.prototype.apply.apply(console.log, [console, arguments]);
}
}
if (console.trace) console.trace();
}

// Build the best logging method possible for this env
// Wherever possible we want to bind, not wrap, to preserve stack traces
function realMethod(methodName) {
if (methodName === 'debug') {
methodName = 'log';
function defaultMethodFactory(methodName, _level, _loggerName) {
if (typeof console !== undefinedType) {
var consoleMethod = console[methodName] || console.log;
if (typeof consoleMethod === "function") {
return consoleMethod.bind(console);
}
pimterry marked this conversation as resolved.
Show resolved Hide resolved
}

if (typeof console === undefinedType) {
return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
} else if (methodName === 'trace' && isIE) {
return traceForIE;
} else if (console[methodName] !== undefined) {
return bindMethod(console, methodName);
} else if (console.log !== undefined) {
return bindMethod(console, 'log');
} else {
return noop;
}
return noop;
}

// These private functions always need `this` to be set properly
Expand All @@ -107,25 +67,6 @@
}
}

// In old IE versions, the console isn't present until you first open it.
// We build realMethod() replacements here that regenerate logging methods
function enableLoggingWhenConsoleArrives(methodName) {
return function () {
if (typeof console !== undefinedType) {
replaceLoggingMethods.call(this);
this[methodName].apply(this, arguments);
}
};
}

// By default, we use closely bound real methods wherever possible, and
// otherwise we wait for a console to appear, and then try again.
function defaultMethodFactory(methodName, _level, _loggerName) {
/*jshint validthis:true */
return realMethod(methodName) ||
enableLoggingWhenConsoleArrives.apply(this, arguments);
}

function Logger(name, factory) {
// Private instance variables.
var self = this;
Expand Down
69 changes: 20 additions & 49 deletions test/console-fallback-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,60 +15,31 @@ function mockConsole() {
define(['../lib/loglevel', 'test/test-helpers'], function(log, testHelpers) {
var originalConsole = window.console;

describe("Fallback functionality:", function() {
describe("with no console present", function() {
beforeEach(function() {
window.console = undefined;
});

afterEach(function() {
window.console = originalConsole;
});

it("silent method calls are allowed", function() {
var result = log.setLevel(log.levels.SILENT);
log.trace("hello");

expect(result).toBeUndefined();
});

it("setting an active level gently returns an error string", function() {
var result = log.setLevel(log.levels.TRACE);
expect(result).toEqual("No console available for logging");
});

it("active method calls are allowed, once the active setLevel fails", function() {
log.setLevel(log.levels.TRACE);
log.trace("hello");
expect().nothing();
});

describe("if a console later appears", function () {
it("logging is re-enabled and works correctly when next used", function () {
log.setLevel(log.levels.WARN);

window.console = mockConsole();
log.error("error");

expect(window.console.log).toHaveBeenCalled();
});
describe("with no console present", function() {
beforeEach(function() {
window.console = undefined;
});

it("logging is re-enabled but does nothing when used at a blocked level", function () {
log.setLevel(log.levels.WARN);
afterEach(function() {
window.console = originalConsole;
});

window.console = mockConsole();
log.trace("trace");
it("silent method calls are allowed", function() {
var result = log.setLevel(log.levels.SILENT);
log.trace("hello");

expect(window.console.log).not.toHaveBeenCalled();
});
expect(result).toBeUndefined();
});

it("changing level works correctly from that point", function () {
window.console = mockConsole();
var result = log.setLevel(log.levels.WARN);
it("setting an active level gently returns an error string", function() {
var result = log.setLevel(log.levels.TRACE);
expect(result).toEqual("No console available for logging");
});

expect(result).toBeUndefined();
});
});
it("active method calls are allowed, once the active setLevel fails", function() {
log.setLevel(log.levels.TRACE);
log.trace("hello");
expect().nothing();
});

describe("with a console that only supports console.log", function() {
Expand Down
Loading
Loading