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

目录

1.开篇

2.nodejs文件操作

3.stream

4.stream演示

5.写日志

6.拆分日志

7.分析日志介绍

8.readline


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

 

【老板要你啥都会系列】| 前端晋升全栈--项目日志_第1张图片 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 、当前时间 戳传入。由于是通过流写入的,效率很高,每次访问都可以写入东西。

【老板要你啥都会系列】| 前端晋升全栈--项目日志_第2张图片


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

你可能感兴趣的:(JavaScript,编程语言,node.js,java)