npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tflog

v1.0.7

Published

tflog

Downloads

24

Readme

打造高可靠的前端日志模块 TFLOG


背景

前端不同于后端服务的一点是运行在用户的设备中,环境不可控,用户操作难以追溯。 碰到用户来反馈问题,往往很难以复现用户的事故现场以及操作历史。

这个时候仅仅是看上报的异信息或者是后台cgi日志无法提供足够多的信息。

前端日志,则是此时最好的解决方案,分布式存储在客户的设备中,按需上报,让最了解业务场景的开发(前端er)输出最详细的日志。


特性

TFLog具有以下特性,并经过理财通线上微信与手Q客户端的每日千万级PV检验,可用于生产环境。

  1. 零依赖
  2. 多维度过滤(命名空间、日志等级和关键词)
  3. 大容量 采用indexedb存储
  4. 高覆盖率 99.7%
  5. 高可靠 99.79%
  6. 有损降级

使用

1.安装

npm install tflog

2.打日志

var TFLog = require('tflog');
// 'mod/ajax'为namespace
var ajaxLog = new TFLog('mod/ajax');
// 三类日志级别
ajaxLog.log(url,{date:'2018-05-30'});
ajaxLog.error('abort ajax');
ajaxLog.warn('depreciate');

3. 读取日志

// collect logs from 3 days before, and earlier than 1 days ago
TFLog.get('3', '1', function(logs) {});

4. 删除日志

TFLog.keep(7); // 保留最近7天的日志,如果不传参数,则清空日志
TFLog.clean(); // 清空日志并删除数据库

技术选型

对于前端日志服务,我们认为有如下4个要素,必须满足

  1. 高覆盖率:保证有用户出现问题,他大概率是有日志的
  2. 高可靠:接口可靠,日志输出不掉包
  3. 大容量:无顾虑打日志,保存更久的日志
  4. 有损降级:业务的辅助类工具,不应该影响业务

出于以上考虑,以及参考一些开源的日志模块实现,我们锁定了 indexedDB 存储。

注:以下数据皆来自于用户访问微信客户端与手Q客户端,及在PC打开微信的webview。

覆盖率

按照2018-04-27(周五)的用户访问数据,支持率采用UV计算。 计算可达到支持率达到99.7%。支持率逼近3个9,基本实现用户全覆盖。

可靠性

通过统计TFLogtry catchindexeddb三个异常异步回调接口onerror onabort onblocked所上报的异常日志数量来衡量本模块的可靠性

以下数据采集自2018-05-30(周三)

可靠度(注释: 分母为支持indexeddb的用户,因此乘上0.997)

  • 按影响用户数统计 0.9979755857833721
  • 按调用次数(单个PV调用TFLog近40次): 0.999964323326821

通过以上统计可以发现,TFLog具有高可靠的特性,依赖的indexedDB存在一定的不可靠,但在如此高的可靠度上,亦可满足前端日志的需要。

大容量

前端可利用的存储api:cookie,localstorage,sessionStorage,websql,indexedDB

cookie,容量较小仅有4KB左右,并且会被加入到http header中,影响http请求的大小。 sessionStorage则不具备持久化保存的能力,会话结束后被清除。 localstorage有5MB的大小,且可以持久化存储。但是一来广泛被业务使用,共同使用易抢占容量,影响业务。二来,set与get会反复进行JSON与字符串的转化,性能不高。 websql则是一个不错的前端存储,但websql已经被W3C标准抛弃了,明确表示不会再更新和支持,因此非不得已的情况,不要再使用这种存储。

indexedDB则是最完美的方案

  • 大容量,存储容量上限根据草案规定是磁盘所剩空间的50%,而参考各类资料得到的数据是至少在50MB以上。持久化存储
  • 不需要像localstorage反复在JSON与字符串直接进行转化
  • 接口异步,不阻塞业务脚本

因此,在如此大容量选择这一条上,indexedDB似乎也是唯一选择。

有损降级

日志模块作为前端的一个辅助类工具,不应该影响到主流程。

因此,在设备不支持时,应该降级为只利用console输出而不持久化保存。 而在因为indexedDB不可靠而导致丢出异常时,在以本次PV过程中有损降级,拒绝掉之后调用indexedDB的请求,以避免频繁报错。


打磨优化

并行改串行

indexeddb为异步的协议,一开始的过程中,我们采用并行的方式记录日志。 但是当一个事务过程中出现问题时,经常是并行事务全部报异常。 因此,为了降低异常率,同时也是为了数据入库的顺序,我们将此处改为了串行。

前端日志的场景下,不会存在短时间内大量调用的情况,因此串行带来的性能损耗并不会影响到日志模块。

满容处理

indexeddb是前端数据库,容量上相比于其他传统缓存localstorage,sessinStorage,cookie更具有优势,但是再大的容量也得考虑满的情况。 因此我们有如下2种操作避免满容,以及对满容进行处理

保存近7天日志

考虑到日志的时效性,太早的日志往往对我们没有什么价值。我们会清理7天之前的日志,来避免日志的数量不至于无限增长。

满容删库

在保存近7天日志的策略下,仍然有部分用户会报出溢出无法写入的异常。 因此,当用户满容时,我们直接进行删库的操作。

而满容有2种情况,一类是打开indexedDb服务,即报满容的错误,第二类是事务过程中,碰到满容。以下为监测满容并进行处理的代码。

    // 监听onerror
    var request = window.indexedDB.open(varStorage.database,1);
    request.onerror = function (event) {
        if (event.target.error && event.target.error.name == 'QuotaExceededError') {
            // 每天100+条
            // Encountered full disk while opening backing store for indexedDB.open.
            clean();
        }
    };
    // 监听事务的 onabort事件,此处
    var transaction = varStorage.db.transaction(['logs'], IDBTransaction.READ_WRITE || 'readwrite');
    transaction.onabort = function (event) {
        // 当事务是因为abort被取消时,transaction.onerror也会收到冒泡,此处屏蔽单独在onabort中进行处理
        event.stopPropagation();
        if (event.target.error && event.target.error.name == 'QuotaExceededError') {
            // 存储满了,则全部清除 每日3K条
            // Encountered disk full while committing transaction.
            // An attempt was made to add something to storage that exceeded the quota
            clean();
        }
    }
    // 满容的情况下进行删库处理,删库代码如下
    function clean(){
        varStorage.db && varStorage.db.close(); // 可能在打开的时候就失败 此时db尚未赋值
        var request = window.indexedDB.deleteDatabase(varStorage.database);
        request.onerror = function (event) {
            // 1. Internal error opening backing store for indexedDB.deleteDatabase.
            // 2. Internal error deleting database.
            return throwError('clean_error', event.target.error); // 每天200+
        };
        request.onsuccess = function (event) {};
    }

通过监控异常,我们得到clear_error的情况每天仍然有200+异常上报。为此,我们再对这里的成功与失败的比例进行了统计。一下为统计结果。

| 回调事件 |释义| pv | uv | | ------------ | ------------|------------ |------------ | |transaction.onabort |事务中因此满容被取消的|7160 | 1142 | |indexedDB.open.onerror|打开数据库时就因为满容被取消的|266|41 | |deleteDatabase.success |删除成功的|6,931 | 1,076 | |deleteDatabase.error |删除失败的|340 | 66 |

重写console

在既有的业务中,已经存在部分关键节点利用console的方式进行输出,我们通过重写console的方式来达到丰富日志信息的目的。

在重写console的过中也碰到了如下异常,需要避免。 console.log.apply(this,[11])在部分机型下会报出异常TypeError: Illegal invocation,必须写为console.log.apply(console,[11])

重写console代码与TFLog可分别加载,理财通的实践中,将重写console的部分写在head中,以保证所以脚本的console输出都被记录下,而TFLog则在基础模块中进行加载。以此尽可能减少对性能的影响。

加强代码健壮性

  • 各个接口包裹住 try catch,避免因为未知的异常抛出而影响主流程逻辑
  • 保持不信任的原则,取深层次属性时,每一步验证当前对象不为空。例如cursor.value.time按照我们的代码,则不会为空,可是实际上每天出现很多异常由此未加判断导致

indexedDB在iframe使用报错

理财通的跨域方案采用iframe加载中间页,中间页通过postMessage传输所需要的信息,而indexeddb在iframe中使用会异常,此处之前忘记处理导致丢出异常,整个脚本停止运行,造成无法跨域传输信息。

查阅资料后,在是否支持indexeddb中加入如下判断,如果在iframe中则表示不支持indexeddb

    if (self != top){ // indexedb 不支持 iframe
        return false;
    }

避免close后再读取事件属性

IOS: InvalidStateError: DOM IDBDatabase Exception 11: An operation was called on an object on which it is not allowed or at a time when it is not allowed. Android: Uncaught InvalidStateError: Failed to read the 'error' property from 'IDBRequest': The request has not finished.

indexeddb操作结束后,不可在读取error属性

    request.onblocked = function (event) {
        // "Error: Failed to read the 'error' property from 'IDBRequest': The request has not finished.
        // 这里无法读取 event.target.error属性,因为请求已经结束。因此会报错
        return throwError('indexeddb_init_blocked');
    }

异常分析

window pc 微信webview

user-agent为Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.884.400 QQBrowser/9.0.2524.400,即在window系统的pc 微信webview上打开我们理财通,报错集中如下表。

| descriptor | total(异常总数) | ip_total(影响ip数量) | | ------------ | ------------ |------------ | | protocol indexeddb is prevented.:Version change transaction was aborted in upgradeneeded event handler. | 19257 | 4863 | | indexeddb_record_transaction_onabort:QuotaExceededError | 2479 | 1253 | | indexeddb_init_success_onclose | 1 | 1 |

ios9.3以下系统

IOS系统版本9.3及以下报错集中,且报错信息为UnknownError,无法获取到具体的信息。目前IOS系统版本已经更新到11.3以上,相信这部分问题会随着系统版本的不断升级换代,会逐步减少以至于消失。

| descriptor | total(异常总数) | ip_total(影响ip数量) | | ------------ | ------------ |------------ | | indexeddb_record_transaction:UnknownError | 18031 | 2306 | | indexeddb_record_transaction_onabort:UnknownError | 252 | 19 | | protocol indexeddb is prevented.:UnknownError| 39 | 13 | | unable to locate logs earlier than 7d.:UnknownError| 14 | 14 |

异常分析小结

异常操作系统分布统计如下

| count(1) | os_type | | ------------ | ------------ | | 19704 | android | | 26799 | ios | | 21737 | window pc|

背景:业务主要集中于手Q与微信客户端内。

  • PC打开微信webview的场景很少,此部分异常对于我们来说可以忽略。
  • IOS系统报的异常集中于低版本系统,随着系统版本不断的更新换代,这部分异常也会逐渐消失。
  • Android系统的异常分布则更为分散,暂未观察到无机型or系统版本的集中表现

参考资料

  1. indexeddb.js
  2. w3c Indexed Database API 2.0
  3. logline