【老板要你啥都会系列】| 前端晋升全栈--项目日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 日志包含什么访问人数啊、峰值啊、 bug 啊什么的,如果没有日志那么很容易失控。 访问日志可以参考我们 http-server ,每次访问都会有这些东西。

1.开篇

  日志包含什么访问人数啊、峰值啊、bug 啊什么的,如果没有日志那么很容易失控。 访问日志可以参考我们 http-server,每次访问都会有这些东西。自定义日志是则并不是每次访问都打印的,根据情况或自己的需要,有点像 console.log。

日志:

  • 系统没有日志,就等于人没有眼睛——抓瞎
  • 第一,访问日志 access log ( server端最重要的日志)
  • 第二,自定义日志(包括自定义事件、错误记录等)

开发的话自然是打印在控制台,而上线了当然是要把日志保存到文件中。 如果不用 stream 的话,直接操作文件会很大的消耗 cpu 和内存。

目录

  • nodejs文件操作,nodejs stream
  • 日志功能开发和使用
  • 日志文件拆分,日志内容分析

日志文件很大自然不可能放到 redis(占超级多内存而且也是异步的,没必要马上记日志)mysql 的话需要表结构(B树)才比较合适(而且文件每个地方都可以访问,不必要安 装 mysql 文件)。

nodejs文件操作

  1. 日志要存储到文件中
  2. 为何不存储到mysql中?
  3. 为何不存储到redis中?

2.nodejs文件操作

  新建一个文件夹 file-test ,直接建一个 test1.js ,引入两个 node.js 自带的 fs 和 path 库(因为 Linux 和 windows 的文件目录路径是不一样的,需要这个 path 来统一)。 再建一个 data.text ,随便写点什么作为我们测试的文件。 回到 test1 ,利用 resolve 方法, __dirname 代表当前文件的目录获取到 data 我们就去读取文件, readFile 方法,异步的 (注意获取的是数据其实是二进制,记得转换成字符串)。

 但是按照目前这种写法,虽然可以打印出 data ,倘若这个 data 有 5 个 G 这么大,我们还这样搞,那么势必是比较浪费性能和内存(一个进程最大也就 3G )的。

  先看怎么写入文件,定义写入的文件,定义 option(flag 为 a 代表 append 追加写入,而 w 是直接覆盖)。然后就可以调用 writeFile(包含四个参数:要被写入的文件、写入的内容、 选项、回调函数)。同理,写入也是有耗费性能的情况(每次写入一行都 writeFile,一直 writeFile,就不停的打开文件,而且也很难写入非常大的数据)。再看看另一个,判断文件是否存在,调用 exists 方法,接收文件名和回调,会返回一个布尔值,注意也是异步。

const fs = require('fs' ) 
const path = require( 'path')
const fileName = path.resolve(_dirname, 'data.txt') //拿到要操作的文件
//读取文件
fs.readFile(fileName,(err ,data) => {
  if (err) {
    console. log(err)
    return 
}
    console. log(data.tostring()) //注意拿到的是二进制文件,需要转换成字符串!
})
//写入文件
const content ='三星阿卡丽\n'   //随便写入点东西
const opt =
   flag:'a'
} //定义写入的形式,a代表追加写入
fs .writeFile(fileName, content, opt, (err) => {
   if (err) {
       console.log(err) 
      return
}
})

3.stream

   IO 就是输入输出(input 和 output)。网络 IO 常见于视频播放几个 G,不可能直接下载到客户端再看,一来占用内存,二来带宽问题。IO 实在是慢,读写文件发送网络请求什么的。

IO操作的性能瓶颈:

  1. IO包括"网络IO”和"文件IO"
  2. 相比于CPU计算和内存读写, IO的突出特点就是:慢!
  3. 如何在有限的硬件资源下提高I0的操作效率?

借助下图来说,我们之前操作文件就是直接把整个桶给搬起来到到另一个桶,这就要你力气大(硬件资源超好,带宽超强)。但是在资源有限的情况下,那个管子插进去慢慢流就好,慢慢加载。

2345_image_file_copy_502.jpg

stream

实际上 request response 都是继承了 stream 的一些特性或者说本身就是 stream

4.stream演示

新建一个 stream-test 文件夹,新建一个 test1.js 。其实这个 pipe 就是 Linux 里面的标准输入出,输入啥打印啥,不用管,std 就是标准的意思, in 就是输入嘛, out 就是输出咯。就演示一下管道,输入就是流入嘛,输出就是流出嘛。接下来演示那个直接返回 request 数据,这里我们 post 的 request 内容就是 response 展示的内容, request 和 response 是桶,用管道连接,是流的关系。当然要是输入的很多,就 会一点点的流过去。 接下来是操作文件对象。

var fs = require('fs')
var path = require( 'path')
//两个文件名
var fileName1 = path.resolve(_dirname,
data. txt')
var fileName2 = path.resolve(_dirname, 'data-
bak. txt')
//读取文件的stream 对象
var readStrekm = fs. createReadStream( fi leName1)
//写入文件的stream 对象
var writeStream = fs.createWr iteSt ream(f i LeName2 )
//执行拷贝,通过pipe
readSt ream. pipe (writeSt ream )
//数据读取完成,即拷贝完成
readStream. on( 'end', function () {
console. log('拷贝完成')
})

创建写入文件和读取文件两个对象(桶)读取文件的话是从 stream 传给返回值,这些都是变成桶与桶然后流转过去,效率非常高。

//直接返Erequest数据
const http = require( http' )
const server = http .createserver((req, res) => {
    if (req.method === 'POST') {
   req.pipe(res) //从我们发送的request波到传回来的response,显示在返回结果那里
}
})
server.listen(8008)

创建两个随便的数据文件 data.txt data-bak.txt ,导入这两 个文件,分别创建读与写两个 stream 对象(桶)。这个同样可以监听 data end(这样子就知道确实是一点点读取文件的,而传统的操作是一下子都给拿出来)

//复制文件
const fs = require('fs' )
const path = require('path')
const fileName1 = path.resolve(_ dirname, 'data.txt' )
const fileName2 = path. resolve(_ dirname, 'data-bak.txt')
const readstream = fs .createReadstream(fileName1)
const writestream = fs.createwritestream(fileName2) //拿到对应的文件且创建读写对象
readstream.pipe(writestream) //将读到的文件流入写入的文件(也就是拷贝了)
readstream.on('data', chunk => { 
    console. log(chunk.tostring())
})
readstream.on('end', () => { //监听拷贝完成
console.log('copy done ' )
})
// http请求 文件
const fs = require('fs' )
const path = require('path')
const http = require('http')
const fileName1 = path.resolve(_dirname,'data.txt')
const readstream = fs .createReadstream(fileName1 )
const server = http.createserver((req, res) => {
   if (req.method === 'GET') {
        readstream.pipe(res) //直接将读取到的文件一点点传到返回值那里
}
})
server.listen(8000 )

5.写日志

  在 blog-1 下建一个 logs 文件夹,下面建三个文件:access.log、 event.log、 error.log 。 在 src 下建一个 utils 文件夹,里面建一个 log.js 。定义一个 createWriteStream 函数,就是生成右边的桶被写入),由 于只是传入 xxx.log ,所以还需要再拼接一下路径,在当前目 录(utils)上翻一层再上翻一层(blog-1),找到下面的 logs 文件夹,再找到传入的文件,就能拿到真正的地址, 根据这个地址去创建流对象(追加方式)然后返回整个对象即可。

 

   将 access.log 传入建一个对应的流对象,然后再定义一个要传给外面的函数 access (传入 log 参数)用来写访问日志, 写日志我们统一定义成一个函数 writeLog ,接收流对象和 log,直接调对象的 write 方法,传入需要写的内容即可记得换行),在 access 调用这个方法即可,其它的日我

们就不管了,也是一样的道理。 那 么 怎 么 去 用 呢 ? 回 到 aoo.js 获 取 access 方 法 , 在serverHandle 使用,把 method 、 url 、 user-agent 、当前时间 戳传入。由于是通过流写入的,效率很高,每次访问都可以写入东西。

2345_image_file_copy_503.jpg

6.拆分日志

  • 日志内容会慢慢积累,放在一个文件中不好处理
  • 按时间划分日志文件,如2019-02-10.access.log
  • 实现方式: linux的crontab命令,即定时任务

这个由于服务器基本都是 Linux 和类 Linux 的,定时任务的话 windows 可能没办法实现,所以这一块可以了解下即可,主 要是运维的搞。 解释一下*代表什么意思,第一个*代表分钟(如果不写具体 的值保持*就代表忽略,比如 1 * * * *就代表每天的第一分钟执行这个命令)第二个*代表小时(12***代表每天的第二个小时的第 1 分钟执行)第三个是日期第四个是月份第五个是 星期。command 就是一个 shell 脚本。

crontab:

  • 设置定时任务,格式: **** * command
  • 将access.log拷贝并重命名为2019-02-10.access.log
  • 清空access.log文件,继续积累日志

这个完全不需要修改代码,所以肯定是运维来搞,不过了解也是可以的。Node.js 当然也能做这个,但是就比操作系统隔了一层,不如直接通过操作系统的 shell 脚本来操作更加便捷 和高效(也好分离代码)。 回到 utils ,建一个 copy.sh (即 shell 脚本),第一行是固定的即 shell 的执行文件,将 logs 的路径拷贝过去, cd 到 logs , 拷贝 access.log 重命名为当前时间的 access.log 。 echo 移动空字符串到 access.log 相当于清空 access.log 。然后在 Linux 下面执行就行了!

7.分析日志介绍

接下来就是使用 crontab 了,因为前面已经编写好了 shell 脚本,通过输入 crontab -e 进入编辑器,设置时间,执行脚本的时候需要将整个脚本的路径拷贝过去才行。

日志分析:

  1. 如针对access.log日志,分析chrome的占比
  2. 日志是按行存储的, - -行就是一条日志
  3. 使用nodejs的readline ( 基于stream , 效率高)

通过 readline 可以一行行的去查看日志,我们先去不同浏览器运行下不同的地址,创造出不一样的 logs。


8.readline

获取到不同浏览器的日志后,我们回到 utils 下面建一个readline.js,引入 fs 、 path 、 readline 。拿到 access.log ,并且 基于这个建一个 readStream (因为是读操作)。再调用 createInterface 创一个 readline 对象,输入就是流对象。 定义一个储存 chrome 数量的变量和储存总数的变量, on 监 听 line ,每读完一行就会触发。通过 -- 切割数据,第 3 个即数组[2] 就是有关浏览器信息的,看看否包含 Chrome 决定加减。

const fs = require( ' fs' )
const path = require( 'path' ) 
const readline = require('readline')
//创建流对象(读取)
const fileName = path. join(__ dirname, '../', ' ../', 'logs' , access.log' )
const readstream = fs.createReadstream( fileName)
//创建readLine对象
const rl = readline.Interface({
   input: readstream 
})
//定义存放浏览器类型的变量
let chromeNum = 0
letsum=e


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6天前
|
Cloud Native 前端开发 JavaScript
前端开发者必看:不懂云原生你就OUT了!揭秘如何用云原生技术提升项目部署与全栈能力
【10月更文挑战第23天】随着云计算的发展,云原生逐渐成为技术热点。前端开发者了解云原生有助于提升部署与运维效率、实现微服务化、掌握全栈开发能力和利用丰富技术生态。本文通过示例代码介绍云原生在前端项目中的应用,帮助开发者更好地理解其重要性。
30 0
|
10天前
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
3天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
15 1
|
9天前
|
JavaScript 前端开发 测试技术
前端全栈之路Deno篇(五):如何快速创建 WebSocket 服务端应用 + 客户端应用 - 可能是2025最佳的Websocket全栈实时应用框架
本文介绍了如何使用Deno 2.0快速构建WebSocket全栈应用,包括服务端和客户端的创建。通过一个简单的代码示例,展示了Deno在WebSocket实现中的便捷与强大,无需额外依赖,即可轻松搭建具备基本功能的WebSocket应用。Deno 2.0被认为是最佳的WebSocket全栈应用JS运行时,适合全栈开发者学习和使用。
|
11天前
|
缓存 前端开发 JavaScript
前端的全栈之路Meteor篇(二):容器化开发环境下的meteor工程架构解析
本文详细介绍了使用Docker创建Meteor项目的准备工作与步骤,解析了容器化Meteor项目的目录结构,包括工程准备、环境配置、容器启动及项目架构分析。提供了最佳实践建议,适合初学者参考学习。项目代码已托管至GitCode,方便读者实践与交流。
|
10天前
|
存储 前端开发 JavaScript
前端的全栈之路Meteor篇(四):RPC方法注册及调用-更轻量的服务接口提供方式
RPC机制通过前后端的`callAsync`方法实现了高效的数据交互。后端通过`Meteor.methods()`注册方法,支持异步操作;前端使用`callAsync`调用后端方法,代码更简洁、易读。本文详细介绍了Methods注册机制、异步支持及最佳实践。
|
10天前
|
前端开发 JavaScript 中间件
前端全栈之路Deno篇(四):Deno2.0如何快速创建http一个 restfulapi/静态文件托管应用及oak框架介绍
Deno 是由 Node.js 创始人 Ryan Dahl 开发的新一代 JavaScript 和 TypeScript 运行时,旨在解决 Node.js 的设计缺陷,具备更强的安全性和内置的 TypeScript 支持。本文介绍了如何使用 Deno 内置的 `Deno.serve` 快速创建 HTTP 服务,并详细讲解了 Oak 框架的安装和使用方法,包括中间件、路由和静态文件服务等功能。Deno 和 Oak 的结合使得创建 RESTful API 变得高效且简便,非常适合快速开发和部署现代 Web 应用程序。
|
10天前
|
JSON 分布式计算 前端开发
前端的全栈之路Meteor篇(七):轻量的NoSql分布式数据协议同步协议DDP深度剖析
本文深入探讨了DDP(Distributed Data Protocol)协议,这是一种在Meteor框架中广泛使用的发布/订阅协议,支持实时数据同步。文章详细介绍了DDP的主要特点、消息类型、协议流程及其在Meteor中的应用,包括实时数据同步、用户界面响应、分布式计算、多客户端协作和离线支持等。通过学习DDP,开发者可以构建响应迅速、适应性强的现代Web应用。
|
11天前
|
JavaScript 前端开发 Docker
前端的全栈之路Meteor篇(一):开发环境的搭建 -全局安装或使用容器镜像
本文介绍了如何搭建 Meteor 开发环境,包括全局安装 Meteor 工具和使用 Docker 镜像两种方法,以及创建和运行一个简单的 Meteor 项目的基本步骤。 Meteor 是一个全栈 JavaScript 框架,适用于构建实时 Web 应用程序。文章还提供了遇到问题时的解决建议和调试技巧。
|
10天前
|
JavaScript 前端开发 Serverless
前端全栈之路Deno篇:Deno2.0与Bun对比,谁更胜一筹?可能Deno目前更适合serverless业务
在前端全栈开发中,Deno 2.0 和 Bun 作为新兴的 JavaScript 运行时,各自展现了不同的优势。Deno 2.0 重视安全性和多平台兼容性,尤其是对 Windows 的良好支持和原生 TypeScript 支持;而 Bun 则以卓越的性能和简便的开发体验著称,适合快速迭代的小型项目。两者在不同场景下各具特色,Deno 更适合企业级应用和serverless,Bun 则适用于追求速度的项目。