Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Last active August 15, 2019 19:18
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save amcgregor/d964e2a7291b9aa9e25ebea88bb5e7d7 to your computer and use it in GitHub Desktop.
JavaScript / ES6 sufficient to polyfill missing window.console (wholesale, or specific missing methods), identify local development vs. production, squelch certain logging operations in production, and rote console interactions (in non-file: protocol environments) to the back-end server for archival, analytics, etc.
"use strict";!function(){const e=new RegExp("^"+["([^.].)+local","([^.].)+example","([^.].)+test","([^.].)+internal","([^.].)*localhost","127.0.0.1","::1"].join("|")+"$","i"),o="file:"==window.location.protocol||e.test(window.location.hostname),i=()=>{},n=(e,...o)=>{fetch(`/meta/collect/${e}`,{method:"POST",mode:"same-origin",cache:"no-cache",credentials:"same-origin",redirect:"error",referrer:"client",headers:{"Content-Type":"application/json"},body:JSON.stringify({args:o})})},t=["assert","clear","count","countReset","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeLog","timeStamp","timeline","timelineEnd","trace","warn"],r=["debug","error","exception","info","log","table","trace","warn"],l=["debug","info","log"];var c=window.console=window.console||{},a={};for(let e of t)c[e]||(c[e]=i.bind(c));if(!o)for(let e of l)c[e]=i.bind(c);if("file:"!=window.location.protocol)for(let e of r)a[e]=c[e],l.includes(e)?c[e]=n.bind(c,e):c[e]=((...o)=>{n(e,...o),a[e](...o)})}();
// https://console.spec.whatwg.org
// https://github.com/whatwg/console
// http://nkashyap.github.io/console.io/
// console.* Polyfill and, in production, no-op replacement.
(function() {
// An inspired polyfill for standard web browser user agent console interactions.
//
// This serves several purposes:
//
// 1. Add standardized methods missing from the local implementation to prevent code calling these from producing exceptions which halt JavaScript execution.
// 2. Direct certain logging actions at a back-end server collection endpoint, for archival, analytics, and diagnostics.
// 3. Squelch (mute or silence) "noisier" console endpoints to prevent user agents from exposing diagnostic information to end-users.
// Determine if we are running in "local development" or not based on hostname and protocol.
const LOCAL = new RegExp("^" + [
"([^\.]\.)+local", // DNS-SD ("Bonjour") local-network automatic hostnames.
"([^\.]\.)+example", // Reserved for private use.
"([^\.]\.)+test", // Reserved for private use.
"([^\.]\.)+internal", // Reserved for private use.
"([^\.]\.)*localhost", // Loopback interface by name.
"127.0.0.1", // IPv4 loopback interface.
"::1", // IPv6 loopback interface.
].join("|") + "$", "i");
const ISLOCAL = (window.location.protocol == 'file:') || LOCAL.test(window.location.hostname);
const NOOP = () => {};
const COLLECT = (event, ...args) => { fetch(`/meta/collect/${event}`, {
method: 'POST',
mode: 'same-origin',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'error',
referrer: 'client',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({'args': args}),
}) };
const METHODS = [
'assert',
'clear',
'count',
'countReset',
'debug',
'dir',
'dirxml',
'error',
'exception', // Deprecated! Do not use, prefer `error` instead!
'group',
'groupCollapsed',
'groupEnd',
'info',
'log',
'markTimeline', // Deprecated, WebKit-specific! Use timeStamp instead!
'profile',
'profileEnd',
'table',
'time',
'timeEnd',
'timeLog',
'timeStamp', // Deprecated, removed, and WebKit-specific!
'timeline', // Deprecated!
'timelineEnd', // Deprecated!
'trace',
'warn',
];
const INSTRUMENT = [
'debug',
'error',
'exception',
'info',
'log',
'table',
'trace',
'warn',
];
const SILENCE = [ // In "production" silence these logging levels.
'debug',
'info',
'log',
]
var console = (window.console = window.console || {});
var original = {}; // Needs to be exposed to nested contexts, thus not 'let'.
// Only populate ("polyfill") missing (undefined) methods.
for ( let method of METHODS )
if ( !console[method] )
console[method] = NOOP.bind(console);
// "Silence" certain logging levels/methods in production environments.
if ( !ISLOCAL )
for ( let method of SILENCE )
console[method] = NOOP.bind(console);
// Instrument (interpose) specific methods to route those classes of message to the back-end.
// Do not do so if we are served from the file: protocol, as there is no server to accept these notifications.
if ( window.location.protocol != 'file:' )
for ( let method of INSTRUMENT ) {
original[method] = console[method];
if ( SILENCE.includes(method) )
console[method] = COLLECT.bind(console, method);
else
console[method] = (...args) => { COLLECT(method, ...args); original[method](...args) };
}
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment