客户端应用程序_客户端应用程序中的记录错误

客户端应用程序

这篇文章由Panayiotis«pvgr»VelisarakosJames WrightStephan Max进行了同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!

侦探站在尸体上做笔记,周围被潜在的谋杀武器包围

无论是在主动开发期间还是在生产模式下运行时,日志记录都是任何软件应用程序的重要组成部分。

在服务器上工作时,无论选择哪种服务器端语言,都有数百种可用的库,广泛的存储机制以及可用于处理结果日志的各种工具。

但是,当涉及到客户端应用程序时,日志记录通常会被忽略,并且向您开放的选项受到了更大的限制。

在本文中,我将介绍在客户端应用程序中实现日志记录的一些方法。 特别是在JavaScript繁重的单页应用程序(SPA)中。

控制台

记录错误和消息的最常见,最明显的方法就是控制台 。 尽管它似乎是一个原始的解决方案,但毫无疑问,它是开发过程中调试的宝贵工具,因此它可能是一个不错的起点。

console的实现并不总是一致的-尤其是在IE中,也许不足为奇-但总的来说,有四种主要方法可供您使用:

console.log()
console.info()
console.warn()
console.error()

这四种方法中每种方法的输出都略有不同,大多数Web控制台实现(即Dev Tools)都允许您根据所使用的方法来过滤消息。 即日志记录级别。

为了减轻浏览器之间的差异,您可以使用包装函数,例如Paul Irish的包装函数。 WHATWG正在尝试标准化控制台API ,但是该规范仍处于早期阶段,不太可能在一段时间内实现。

提示:如果发现代码中充满console.log()语句,则可能会发现诸如grunt-remove-logginggrunt-strip(对于Grunt)或gulp-strip-debug(对于Gulp)等工具对于移动应用到生产中。

增强控制台

您可以使用几个库对控制台进行“超级充电”。

登出

Logdown是一个很小的库,它为控制台提供了一些增强功能。 您将在此处找到一个演示

Logdown允许您在实例化时指定前缀; 一种可能的用途是按模块分隔您的日志消息,例如:

var uiLogger = new Logdown({prefix: 'MyApp:UI'});
var networkServiceLogger = new Logdown({prefix: 'MyApp:Network'});

然后,您可以按其前缀启用或禁用记录器,例如:

Logdown.disable('MyApp:UI');
Logdown.enable('MyApp:Network');
Logdown.disable('MyApp:*'); // wildcards are supported, too

禁用记录器实际上可以使其静音。

一旦对一个或多个记录器进行了实例化,就可以使用log()warn()info()error()方法记录消息:

var logger = new Logdown();
logger.log('Page changed');
logger.warn('XYZ has been deprecated in favour of 123');
logger.info('Informational message here');
logger.error('Server API not available!');

Logdown还提供Markdown支持:

var logger = new Logdown({markdown: true}); // Technically "markdown: true" isn't required; it's enabled by default
logger.warn('_XYZ_ has been *deprecated* in favour of _123_');
控制台消息

console.message是另一个美化控制台输出的库。

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

这是文档中的快速动画,展示了其某些功能:

console.message在行动

本质上,该库提供了一种可链接的接口,其中包含允许您格式化文本,将消息分组在一起并使它们可折叠,将交互式DOM元素或对象发送到日志(甚至包括图像)的方法。

控制台的局限性

在构建应用程序时,该控制台非常有用,并且可以在您面前打开它,但是除非您碰巧看着用户的肩膀, 并且碰巧他们在浏览器中打开了Web控制台,否则您不会不能看到结果。

相反,我们可以做的是将任何错误(甚至在开发过程中调试消息)发送到某处的服务器,以便我们可以远程访问它们。

其他要考虑的事情

现在,我们已经为您提供了一些解决方案,下面让我们看一些其他注意事项。

捕获全局错误

至少,值得捕获和记录任何未处理的异常。 您可以使用window.onerror做到这一点。 这是一个非常简单的示例:

window.onerror = function(message, file, line) {
  console.log('An error occured at line ' + line + ' of ' + file + ': ' + message);
};

堆栈痕迹

发生错误时, 堆栈跟踪可提供更多详细信息,您可能希望在开发中使用它。 有几个库可以帮助构建它们。

跟踪工具

TraceKit允许您将堆栈跟踪注入异常中,并对它们进行某些处理(例如,将其发送到服务器端日志记录组件),方法是订阅它们。

代码如下所示:

TraceKit.report.subscribe(function yourLogger(errorReport) {
  //send via ajax to server, or use console.error in development
  //to get you started see: https://gist.github.com/4491219
});

然后,在您的应用程序中:

try {
  /*
   * your application code here
   *
   */
  throw new Error('oops');
} catch (e) {
  TraceKit.report(e); //error with stack trace gets normalized and sent to subscriber
}
stacktrace.js

引用该文档, stacktrace.js是“ [a]框架无关的微库,用于在所有Web浏览器中获取堆栈跟踪”。

它提供了一个名为printStackTrace()的方法,您可以在错误处理程序中使用该方法将堆栈跟踪添加到日志记录函数中。 例如,我们可以如下增强服务器端记录器:

function log(data, level) {
  $.post(
    'https://your-app.com/api/logger',
    {
      context     :   navigator.userAgent,
      level       :   level || 'error',
      data         :   data,
      stack_trace :    printStackTrace()
    }
  );
}

将客户端错误记录到服务器

将日志条目发送到服务器具有许多优点:

  1. 您可以从应用程序中捕获日志条目,而无需亲自坐在计算机上(完美地投入生产)
  2. 您可以在同一位置(可能使用相同的工具)管理服务器端和客户端日志
  3. 您可以设置警报(例如,如果发生严重错误,则显示松弛通知或短信)
  4. 控制台不可用或难以查看的地方(例如,使用手机的网络视图时),更容易查看正在发生的情况

让我们看一下几种方法。

滚动自己的服务器端记录器

在某些情况下,最简单的解决方案可能是使用自己的服务器端日志记录机制。

这是使用jQuery的客户端部分的极小示例:

function log(data, level) {
  $.post(
    'https://your-app.com/api/logger',
    {
      context   :   navigator.userAgent,
      level     :   level || 'error',
      data       :   data
    }
  );
}

一些用法示例:

try {
  // some function
} catch (e) {
  log({
    error : e.message
  });
}
log('Informational message here', 'info');

考虑到这一点,下面是一个非常基本的服务器端组件,该示例与Node.js和Express一起使用,并带有出色的Winston日志记录库:

/**
 * Load the dependencies
 */
var express = require( 'express' );
var bodyParser = require('body-parser');
var winston = require( 'winston' );

/**
 * Create the Express app
 */
var app = express();

app.use(bodyParser.urlencoded({ extended: true }));

/**
 * Instantiate the logger
 */
var logger = new ( winston.Logger )({
  transports: [
    new ( winston.transports.Console )(
      { 
        level: 'error'
      }
    ),
    new ( winston.transports.DailyRotateFile )(
      { 
        filename: 'logs/client.log',
        datePattern: '.yyyy-MM-dd'
      }
    )
  ]
});

app.post ('/api/logger', function( req, res, next ) {

  logger.log(
    req.body.level || 'error',
    'Client: ' + req.body.data
  );

  return res.send( 'OK' );

});

var server = app.listen( 8080, function() {
  console.log( 'Listening on port %d', server.address().port );
});

实际上,这种过度简化的记录器存在一些基本限制:

  1. 大多数日志记录机制允许您配置最低日志记录级别,以便可以过滤出某些条目
  2. 它将立即发送日志条目,这可能导致服务器端组件过载

解决第二个问题的更好方法是缓冲日志条目并分批发送。 一种常见的方法是使用localStorage存储日志条目,然后以特定的时间间隔发送日志-基于时间,当达到未决条目数量的特定阈值时,或者当用户关闭窗口或导航到远离您的位置时利用window.onbeforeunload事件应用程序。

为了解决这些问题,让我们看一个现成的解决方案,用于从JS应用程序进行日志记录。

log4javascript

log4javascript基于无处不在的log4j ,它也是已移植到PHP的Java日志记录框架,因此,如果您来自服务器端背景,则可能已经对此有所了解。

log4javascript使用appenders的概念,该概念决定了在调用其日志记录方法之一时会发生什么。 当您拥有大多数现代浏览器提供的开发工具时,默认的PopUpAppender可以说是相当多余的。

也许更有用的是AjaxAppender ,您可以使用它将日志条目发送回服务器。 您可以配置AjaxAppender以一定的时间间隔发送使用分批条目setTimed()使用一定数量的setBatchSize()或当使用卸载窗口setSendAllOnUnload()

可以从Sourceforge下载log4javascript,或者在Github可以使用类似的Log4js。 您可以参考快速入门快速启动和运行。

这是一个例子:

var log = log4javascript.getLogger();
var ajaxAppender = new log4javascript.AjaxAppender('http://example.com/api/logger');
ajaxAppender.setThreshold(log4javascript.Level.ERROR);
ajaxAppender.setBatchSize(10); // send in batches of 10
ajaxAppender.setSendAllOnUnload(); // send all remaining messages on window.beforeunload()
log.addAppender(ajaxAppender);

或者,以特定的时间间隔发送消息:

ajaxAppender.setTimed(true);
ajaxAppender.setTimerInterval(10000); // send every 10 seconds (unit is milliseconds)

其他图书馆

如果您的项目使用jQuery,则可能需要研究jquery logger ,它允许您通过Ajax进行登录。 但是,它不支持批处理。 不过,它确实与Airbrake很好地集成为后端。

loglevel是一个轻量级且可扩展的基于JS的日志记录框架,它通过单独的serverSend插件支持Ajax。

推出自己的批次兼容记录仪

这是一个记录器的简单概念证明,它可以批量发送消息。 它是使用具有ES6功能的原始JavaScript编写的。

"use strict";
class Logger {

  // Log levels as per https://tools.ietf.org/html/rfc5424
  static get ERROR()  { return 3; }
  static get WARN()   { return 4; }
  static get INFO()   { return 6; }
  static get DEBUG()  { return 7; }

  constructor(options) {

    if ( !options || typeof options !== 'object' ) {
      throw new Error('options are required, and must be an object');
    }

    if (!options.url) {
      throw new Error('options must include a url property');  
    }

    this.url         =   options.url;
    this.headers     =   options.headers || [ { 'Content-Type' : 'application/json' } ];
    this.level       =   options.level || Logger.ERROR;
    this.batch_size =   options.batch_size || 10;
    this.messages   =   [];

  }

  send(messages) {    
    var xhr = new XMLHttpRequest();
    xhr.open('POST', this.url, true);

    this.headers.forEach(function(header){      
      xhr.setRequestHeader(
        Object.keys(header)[0],
        header[Object.keys(header)[0]]
      );
    });

    var data = JSON.stringify({
      context   :   navigator.userAgent,
      messages  :   messages
    });    
    xhr.send(data);
  }

  log(level, message) {
    if (level <= this.level) {
      this.messages.push({
        level : level,
        message : message
      });      
      if (this.messages.length >= this.batch_size) {
        this.send(this.messages.splice(0, this.batch_size));        
      }
    }
  }

  error(message) {
    this.log(Logger.ERROR, message);
  }

  warn(message) {
    this.log(Logger.WARN, message);
  }

  info(message) {
    this.log(Logger.INFO, message);
  }

  debug(message) {
    this.log(Logger.DEBUG, message);
  }

}

用法很简单:

var logger = new Logger({
  url : 'http://example.com/api/batch-logger',
  batch_size : 5,
  level : Logger.INFO
});

logger.debug('This is a debug message'); // No effect
logger.info('This is an info message');
logger.warn('This is a warning');
logger.error('This is an error message');
logger.log(Logger.WARN, 'This is a warning');

基于服务器的自托管选项

厄比特

Errbit是用于捕获错误的开源,自托管解决方案。 它在Ruby中实现,并使用MongoDB进行存储。

如果您想快速了解Errbit ,可以使用Chef CookbookDockerfile 。 还有一个在线演示,您可以尝试。

要登录在线演示,请使用电子邮件demo@errbit-demo.herokuapp.com和密码password

基于SaaS服务器的选项

有许多用于日志记录的SaaS解决方案。 这些包括Logglytrack.jsErrorCeptionAirbrakeNew Relic

让我们简要看一下一些这样的解决方案。

Loggly

Loggly是这些SaaS解决方案中的一种。 我将以它为例,因为它很容易并且免费上手。 使用免费计划,您每天最多可以登录200MB,数据存储7天。

要从客户端应用程序使用Loggly,您需要包含以下代码段:

<script type="text/javascript" src="http://cloudfront.loggly.com/js/loggly.tracker.js" async></script>
<script>
  var _LTracker = _LTracker || [];
  _LTracker.push({'logglyKey': 'YOUR-LOGGING-KEY',
  'sendConsoleErrors' : true });
</script>

注意:您需要通过使用Source Setup来将YOUR-LOGGING-KEY替换为应用程序特定的值,该值将在您注册并登录后得到。

如果检查此代码,您会看到_LTracker对象最初被实例化为数组。 这是许多分析库中使用的“填充”技术,这意味着您可以在加载库之前对其调用push() 。 当库可用时,您推送到该阵列的任何错误或消息都将排队等待。

用法很简单:

_LTracker.push(data);

您可以使用它发送一段文本:

_LTracker.push( 'An error occured: ' + e.message );

或者,也许更有用的是,您可以使用JSON-例如:

try {
  // some operation
} catch (e) {
  _LTracker.push({
    level   : 'error',
    message : e.message,
    trace   : e.trace,
    context : navigator.userAgent
  });
}

虽然这是一个非常基本的解决方案,但是您可以简单地使用以下代码捕获错误:

window.onerror = function(message, file, line) {        
  _LTracker.push({
    context: navigator.userAgent,
    error: message,
    file: file,
    line: line
  });
};

这种方法有一些局限性。 如果您的内部版本稍有不同,或者要缩小JS代码,那么行号实际上是没有用的。

您还会在上面的Loggly代码段中注意到sendConsoleErrors设置为TRUE ,这将自动为您记录某些错误,而无需手动发送。 例如,如果RequireJS超时发生,则以下内容将发送到Loggly:

{
  "category": "BrowserJsException",
  "exception": {
    "url": "http://example.com/js/require.js",
    "message": "Uncaught Error: Load timeout for modules: main\nhttp://requirejs.org/docs/errors.html#timeout",
    "lineno": 141,
    "colno": 15
  },
  "sessionId": "xyz-123-xyz-123"
}

{track.js}

{track.js}是另一个用于日志记录的SaaS解决方案。

他们提供免费计划; 它限制为每分钟10个错误,每月10,000次命中,并且您的数据仅存储24小时。 最基本的付费计划是每月29.99美元-您可以在其定价页面上找到更多详细信息。

注意:无论何时初始化库,都会记录“命中”。

进行设置非常简单:

<!-- BEGIN TRACKJS -->
<script type="text/javascript">window._trackJs = { token: 'YOUR-TOKEN-HERE' };</script>
<script type="text/javascript" src="//d2zah9y47r7bi2.cloudfront.net/releases/current/tracker.js" crossorigin="anonymous"></script>
<!-- END TRACKJS -->

在拉入适当文件并初始化库之后,可以使用诸如track()

/**
  * Directly invokes an error to be sent to TrackJS.
  *
  * @method track
  * @param {Error|String} error The error to be tracked. If error does not have a stacktrace, will attempt to generate one.
  */
trackJs.track("Logical error: state should not be null");

try {
  // do something
} catch (e) {
  trackJs.track(e);
}

或使用控制台,该控制台会将消息发送到Web服务:

trackJs.console.debug("a message"); // debug severity
trackJs.console.log("another message"); // log severity

{track.js}可以做更多的事情-请查看文档以获取更多信息。

综上所述

客户端日志通常被忽略,但是可以说与记录服务器端错误同样重要。 但是,毫无疑问,它更难设置。 但是,有很多选择,在本文中我们已经研究了其中许多。

您如何处理客户端应用程序中的日志记录? 您是否开发了自己的方法? 您是否使用此处未涵盖的内容? 在评论中让我知道。

翻译自: https://www.sitepoint.com/logging-errors-client-side-apps/

客户端应用程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java CS客户程序架构是指基于Java语言开发的客户软件的结构和组织方式。在Java CS客户程序架构中,常见的架构模式包括MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)等。 MVC是一种经典的架构模式,将软件分为模型(Model)、视图(View)和控制器(Controller)三层。模型负责数据的存储和操作,视图负责展示用户界面,控制器负责处理用户的操作并根据需要调用模型或视图的相关功能。这种架构模式可以使各个模块之间的职责分离,提高代码的可维护性和可复用性。 MVVM是一种相对较新的架构模式,它在MVC基础上增加了一个ViewModel层,用于连接模型和视图。视图负责展示用户界面,模型负责存储和操作数据,而ViewModel则负责管理模型和视图之间的数据同步和交互。MVVM架构在开发响应式UI和大规模数据驱动应用方面具有优势。 无论采用哪种架构模式,Java CS客户程序通常会包含以下组件或功能: 1. 用户界面:负责与用户进行交互,包括各种界面元素和用户输入的处理。 2. 网络通信:用于与服务器进行通信,包括发送请求和接收响应等功能。 3. 数据处理:负责处理和操作数据,包括从服务器获取数据、本地数据的存储和查询等。 4. 业务逻辑:根据用户的操作和数据的变化,处理各种业务逻辑,进行计算和判断等。 5. 安全性和权限控制:确保身份验证和数据权限的合法性,以保护系统和用户数据的安全。 6. 错误处理和日志记录:处理程序运行过程中可能出现的错误,并记录日志以便后续排查和修复。 7. 可扩展性和规模化:将程序设计为可扩展和易于维护的结构,支持后续功能的添加和系统的规模化。 总的来说,Java CS客户程序架构旨在将软件的不同部分分离,降低耦合度,提高可重用性和可维护性,并满足用户对界面友好性、性能和安全性等需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值