【Node.js从基础到高级运用】十四、Node.js 错误处理与日志记录

引言

在这篇博客文章中,我们将深入探讨Node.js中的错误处理和日志记录的最佳实践。我们会了解如何在Node.js应用程序中有效地捕获和处理错误,并利用日志库如morgan来记录应用程序的活动和错误信息。

第1部分:Node.js中的错误处理

同步代码中的错误处理

在Node.js的同步代码中,我们通常使用try...catch语句来捕获错误。

// 同步代码错误处理示例
try {
  // 尝试执行可能会抛出错误的代码
  let result = someSynchronousOperation();
  console.log('Operation successful:', result);
} catch (error) {
  // 处理错误
  console.error('An error occurred:', error);
}

异步代码中的错误处理

异步代码的错误处理稍微复杂一些,因为错误可能在回调函数中发生。

// 异步代码错误处理示例
fs.readFile('/path/to/file', (err, data) => {
  if (err) {
    // 处理错误
    console.error('Error reading file:', err);
  } else {
    // 正常处理数据
    console.log('File content:', data);
  }
});

Promise中的错误处理

当使用Promise时,我们可以利用.catch()方法来捕获错误。

// Promise中的错误处理示例
someAsyncOperation()
  .then(result => {
    console.log('Operation successful:', result);
  })
  .catch(error => {
    // 处理错误
    console.error('An error occurred:', error);
  });

Express中的错误处理

在Express框架中,错误处理通常通过中间件来实现。

// Express中的错误处理示例
const express = require('express');
const app = express();

// 中间件来捕获同步代码中的错误
app.use((req, res, next) => {
  throw new Error('Something went wrong!');
  next(); // 这行代码不会执行
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error('Error:', err);
  res.status(500).send('Internal Server Error');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

第2部分:日志记录

为什么需要日志记录

日志记录是应用程序监控和故障排除的关键组成部分。它可以帮助开发者了解应用程序的运行状态和诊断问题。

使用console进行简单日志记录

对于简单的应用程序,使用console.log()console.error()可能就足够了。

// 使用console记录日志
console.log('This is an informational message');
console.error('This is an error message');

使用morgan进行HTTP请求日志记录

对于Web应用程序,我们通常希望记录HTTP请求。Morgan是一个流行的日志中间件,可以很容易地集成到Express应用程序中。

// 使用morgan记录HTTP请求
const express = require('express');
const morgan = require('morgan');

const app = express();
app.use(morgan('combined')); // 'combined'是预定义的日志格式

app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这里插入图片描述

Morgan预定义的格式化选项

1. combined
combined格式提供了Apache服务器日志的标准组合格式,包括许多有用的信息,适合用于生产环境
它包含以下信息:

  • 客户端地址 (remote-addr)
  • 认证用户 (remote-user)
  • 时间戳 ([date])
  • 请求行 (“method url HTTP/version”)
  • HTTP状态码 (status)
  • 响应内容的长度 (content-length)
  • 引用页 (“referrer”)
  • 用户代理 (“user-agent”)

2. common
common格式类似于combined,但它不包括引用页(“referrer”)和用户代理(“user-agent”)。
它包含以下信息:

  • 客户端地址 (remote-addr)
  • 认证用户 (remote-user)
  • 时间戳 ([date])
  • 请求行 (“method url HTTP/version”)
  • HTTP状态码 (status)
  • 响应内容的长度 (content-length)

3. dev
dev格式主要用于开发环境,因为它的输出是彩色的,便于区分不同的HTTP状态码。

它包含以下信息:

  • 请求方法和URL (`method url)
  • HTTP状态码 (status),如果是4xx或5xx则以红色显示
  • 响应时间 (response-time)

自定义日志记录

在复杂的应用程序中,您可能需要更高级的日志记录解决方案,如WinstonBunyan

// 使用Winston进行自定义日志记录
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

logger.info('This is an informational message');
logger.error('This is an error message');

将会在根目录生成log文件:
在这里插入图片描述

第3部分:结合错误处理与日志记录

结构化错误信息

为了更有效地记录错误,我们可以创建一个结构化的错误对象。

// 结构化错误信息
class AppError extends Error {
  constructor(message, status) {
    super(message);
    this.status = status;
    this.isOperational = true; // 标记为可预见的操作错误
  }
}

将错误信息记录到日志中

我们可以将错误对象与日志系统结合起来,以便更详细地记录错误信息。

// 将错误信息记录到日志中
function handleError(err) {
  logger.error({ message: err.message, stack: err.stack, status: err.status });
}

// 在应用程序中使用
try {
  // 产生错误
  throw new AppError('Something went wrong!', 500);
} catch (err) {
  handleError(err);
}

在这里插入图片描述
测试用例:

const fs = require('fs');
const winston = require('winston');

// 配置日志记录器
const logger = winston.createLogger({
  level: 'error',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log' })
  ]
});

// 错误记录示例
function readFileAndLog(path) {
  fs.readFile(path, (err, data) => {
    if (err) {
      // 记录错误到日志
      logger.error('Error reading file', { path: path, error: err });
      // 进一步的错误处理...
    } else {
      // 处理文件内容...
    }
  });
}

第四部分:错误通知(警报)、错误恢复策略

错误通知

对于某些关键错误,仅仅记录到日志可能不够,还需要实时通知到开发者或运维团队。这可以通过邮件、短信、即时消息等方式实现。

const nodemailer = require('nodemailer');

// 配置邮件发送器
const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: 'your-email@gmail.com',
    pass: 'your-password'
  }
});

// 错误通知示例
function notifyError(error) {
  const mailOptions = {
    from: 'your-email@gmail.com',
    to: 'dev-team-email@example.com',
    subject: 'Application Error Alert',
    text: `An error has occurred: ${error.message}`
  };

  transporter.sendMail(mailOptions, function(err, info) {
    if (err) {
      console.error('Error sending email:', err);
    } else {
      console.log('Error notification sent:', info.response);
    }
  });
}

错误恢复策略

错误恢复策略是指当错误发生时,如何保证系统能够继续运行或尽快恢复到正常状态。这可能包括重试失败的操作、切换到备份服务、释放资源等。

// 错误恢复策略示例
function operationWithRetry(operation, maxAttempts) {
  let attempts = 0;

  function attempt() {
    operation((err, result) => {
      if (err) {
        attempts++;
        if (attempts < maxAttempts) {
          console.log(`Attempt ${attempts}: retrying operation`);
          attempt(); // 重试操作
        } else {
          console.error('Operation failed after retries:', err);
          // 进行其他恢复操作...
        }
      } else {
        // 操作成功
      }
    });
  }

  attempt();
}

测试用例

编写测试用例时,应当模拟不同的错误场景,并验证错误处理流程是否按预期工作。

const assert = require('assert');

// 测试错误记录
readFileAndLog('/non/existent/file');
// 确认错误.log文件中记录了错误信息

// 测试错误通知
notifyError(new Error('Test Error'));
// 确认开发团队收到了错误通知邮件

// 测试错误恢复策略
let operationCalled = 0;
const mockOperation = (callback) => {
  operationCalled++;
  if (operationCalled < 3) {
    callback(new Error('Operation failed'));
  } else {
    callback(null, 'Success');
  }
};

operationWithRetry(mockOperation, 5);
assert.strictEqual(operationCalled, 3, 'Operation should succeed on the third attempt');

assert.strictEqual 是 Node.js assert 模块提供的一个方法,用来测试两个值是否严格相等。这里的“严格相等”指的是它们的类型和值都必须完全匹配,这与 JavaScript 中的===运算符相同。
在这个例子中,如果 operationCalled不等于 3,那么 assert.strictEqual 会抛出一个错误,并显示提供的错误信息(‘Operation should succeed on the third attempt’)

总结

在Node.js应用程序中,正确地处理错误和记录日志是至关重要的。它不仅有助于开发和调试过程,也是生产环境中保证应用稳定性和可维护性的关键。通过本文的介绍,您应该能够在您的Node.js应用程序中实现高效的错误处理和日志记录策略。

参考资料

Node.js官方文档
Express官方文档
Morgan npm页面
Winston npm页面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/467696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Node.js从基础到高级运用】十三、NodeJS中间件高级应用

在现代web开发中&#xff0c;Node.js因其高效和灵活性而备受青睐。其中&#xff0c;中间件的概念是构建高效Node.js应用的关键。在这篇博客文章中&#xff0c;我们将深入探讨Node.js中间件的高级应用&#xff0c;包括创建自定义中间件、使用第三方中间件等。我们将从基础讲起&a…

CTF题型 Http请求走私总结Burp靶场例题

CTF题型 Http请求走私总结&靶场例题 文章目录 CTF题型 Http请求走私总结&靶场例题HTTP请求走私HTTP请求走私漏洞原理分析为什么用前端服务器漏洞原理界定标准界定长度 重要!!!实验环境前提POST数据包结构必要结构快速判断Http请求走私类型时间延迟CL-TETE-CL 练习例题C…

三 C#插入排序算法

简介 插入排序算法是一种简单、直观的排序算法&#xff0c;其原理是将一个待排序的元素逐个地插入到已经排好序的部分中。 插入排序实现原理 插入排序算法是一种简单、直观的排序算法&#xff0c;其原理是将一个待排序的元素逐个地插入到已经排好序的部分中。 具体实现步骤…

Java类的初始化顺序

请直接看原文: Java类的初始化顺序_java创建顺序-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 对于静态变量、静态初始化块、变量、初始化块、构造器&#xff0c;它们的…

滴答拍摄影项目|基于Spring Boot框架+ Mysql+Java+ Tomcat的滴答拍摄影项目设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

centos创建并运行一个redis容器 并支持数据持久化

步骤 : 创建redis容器命令 docker run --name mr -p 6379:6379 -d redis redis-server --appendonly yes 进入容器 : docker exec -it mr bash 链接redis : redis-cli 查看数据 : keys * 存入一个数据 : set num 666 获取数据 : get num 退出客户端 : exit 再退…

elk收集k8s微服务日志

一、前言 使用filebeat自动发现收集k8s的pod日志&#xff0c;这里分别收集前端的nginx日志&#xff0c;还有后端的服务java日志&#xff0c;所有格式都是用json格式&#xff0c;建议还是需要让开发人员去输出java的日志为json&#xff0c;logstash分割java日志为json格式&#…

java实现word转pdf

引入依赖包 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.2.5.RELEASE</version></dependency><dependency><groupId…

jQuery+CSS3自动轮播焦点图特效源码

jQueryCSS3自动轮播焦点图特效源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 下载地址 jQueryCSS3自动轮播焦点图特效源码

day03vue学习

day03 一、今日目标 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.综合案例-小黑记账清单 列表渲染添加/删除饼图渲染 3.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 4.综合案例-小兔仙首页 拆分模块-局部注册结构样式完善…

LeetCode链表hard 有思路?但写不出来?

给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值…

功能齐全的免费 IDE Visual Studio 2022 社区版

面向学生、开放源代码和单个开发人员的功能齐全的免费 IDE 下载地址 Visual Studio 2022 社区版 - 下载最新的免费版本 Visual Studio 2022 Community Edition – Download Latest Free Version 准备安装 选择需要安装的程序 安装进行中 使用C学习程序设计相关知识并培养编程…

改变input placeholder的样式 (适用于vue uniapp 中的input textarea)

如下控制 <textarea name"" placeholder"请输入您要反馈的问题&#xff0c;以便我们为您解决" placeholder-style"font-weight: 500;font-size: 27rpx;color: #999999;" id"" cols"30" rows"10"></text…

电话机器人语音识别用哪家更好精准度更高。

语音识别系统的选择取决于你的具体需求&#xff0c;包括但不限于识别精度、速度、易用性、价格等因素。以下是一些在语音识别领域表现较好的公司和产品&#xff1a; 科大讯飞&#xff1a;科大讯飞是中国最大的语音识别技术提供商之一&#xff0c;其语音识别技术被广泛应用于各…

诺视科技完成亿元Pre-A2轮融资,加速Micro-LED微显示芯片商业化落地

近日&#xff0c;Micro-LED微显示芯片研发商诺视科技&#xff08;苏州&#xff09;有限公司&#xff08;以下简称“诺视科技”&#xff09;宣布完成亿元Pre-A2轮融资&#xff0c;本轮融资由力合资本领投&#xff0c;老股东盛景嘉成、汕韩基金以及九合创投持续加码&#xff0c;这…

Ubuntu 搭建gitlab服务器,及使用repo管理

一、GitLab安装与配置 GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的Web服务。 1、安装Ubuntu系统&#xff08;这个教程很多&#xff0c;就不展开了&#xff09;。 2、安装gitlab社区版本&#xff0c;有需…

后端工程师快速使用vue和Element

文章目录 Vue1 Vue概述2 快速入门3 Vue指令3.1 v-bind和v-model3.2 v-on3.3 v-if和v-show3.4 v-for3.5 案例 4 生命周期 Element快速使用1 Element介绍2 快速入门3 当前页面中嵌套另一个页面案例代码案例截图 Vue 1 Vue概述 通过我们学习的htmlcssjs已经能够开发美观的页面了…

微服务技术栈SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式(五):分布式搜索 ES-下

文章目录 一、数据聚合1.1 聚合种类1.2 DSL实现聚合1.3 RestAPI实现聚合1.4 演示&#xff1a;多条件聚合 二、自动补全2.1 拼音分词器2.2 自定义分词器2.3 DSL自动补全查询2.5 实现酒店搜索框自动补全2.5.1 修改酒店索引库数据结构2.5.2 RestAPI实现自动补全查询2.5.3 实战 三、…

yocto编译测试

源码下载 git clone -b gatesgarth git://git.yoctoproject.org/poky lkmaolkmao-virtual-machine:~/yocto$ git clone -b gatesgarth git://git.yoctoproject.org/poky Cloning into poky... remote: Enumerating objects: 640690, done. remote: Counting objects: 100% (13…

C++开发基础——函数模板

一&#xff0c;函数模板 1.基础概念 模板编程是C中泛型编程的基础。 一个模板可以是创建类或者函数的蓝图。 模板编程分两种&#xff0c;分别是算法抽象的模板、数据抽象的模板。算法抽象的模板以函数模板为主&#xff0c;数据抽象的模板以类模板为主。 基于函数模板生成的…