<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何使用 Go進(jìn)行日志分析,并生成excel報(bào)表?

          共 6413字,需瀏覽 13分鐘

           ·

          2022-01-15 01:05

          這周工作的時(shí)候接到了一個(gè)需求,需要對(duì)一個(gè)日志文件進(jìn)行分析,分析請(qǐng)求次數(shù)以及耗費(fèi)的時(shí)間平均時(shí)間等信息,整理成excel表格,方便分析做優(yōu)化。剛拿到這個(gè)需求的時(shí)候,著實(shí)有點(diǎn)懵逼。那么多日志,我該怎么分析呢?

          該使用什么工具去分析呢。最后還要生成excel表格。哇,給我愁壞了。

          所以我開(kāi)始并沒(méi)有直接去做需求,而是去查資料、問(wèn)同事、朋友,怎么做日志分析。

          確實(shí)搜到了一些日志分析的方法:awk、python。無(wú)疑是用腳本來(lái)做。但是我對(duì)這些不太熟悉呀,而且只有一下午的時(shí)間去做。最后我選擇了使用golang來(lái)做。相比于其他,我對(duì)golang更熟悉。

          確定了語(yǔ)言,我就開(kāi)始分析日志了,下面我就來(lái)詳細(xì)介紹一下我是怎么使用go完成的日志分析,并成功生成excel表格。

          #?1. 前期準(zhǔn)備

          因?yàn)楣镜膌og不能在這里直接展示,所以本次教程我自己生成了幾個(gè)測(cè)試log。

          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}
          {"httpRequest":{"request":"method:post,path:/api/user/login"},"params":{"query":"username=asong&password=123456"},"timings":{"evalTotalTime":0.420787431}}

          這些log正常都在一行的,因?yàn)閙arkdown顯示問(wèn)題,顯示了多行。

          #?2. 日志分析

          分析之前,先看一下我們的需求:分析每個(gè)請(qǐng)求的次數(shù),查詢參數(shù),平均時(shí)間。

          確定了需求,下面我們開(kāi)始對(duì)日志進(jìn)行分析。每一行代表一個(gè)完整的日志請(qǐng)求。每一行日志都是一個(gè)json字符串,這樣看起來(lái)確實(shí)不方便,我們格式化一下來(lái)看一下。

          {
          ????"httpRequest":{
          ????????"request":"method:post,path:/api/user/login"
          ????},
          ????"params":{
          ????????"query":"username=asong&password=123456"
          ????},
          ????"timings":{
          ????????"evalTotalTime":0.420787431
          ????}
          }

          這樣看起來(lái)就很方便了,層次結(jié)構(gòu)一眼就能看出來(lái)。我們要統(tǒng)計(jì)請(qǐng)求的次數(shù),可以通過(guò)requrst這個(gè)字段判斷是否是同一個(gè)請(qǐng)求。query這個(gè)字段代表的是查詢參數(shù),evalTotalTime這個(gè)字段需要求和,然后求出平均數(shù)。日志分析好了,下面就是實(shí)現(xiàn)部分了。

          #?3. 代碼實(shí)現(xiàn)

          ?代碼實(shí)現(xiàn)日志分析

          這里我使用一個(gè)map來(lái)存放不同的請(qǐng)求,以請(qǐng)求作為key,請(qǐng)求次數(shù)、時(shí)間等作為value,不過(guò)這里存的時(shí)間所有請(qǐng)求的時(shí)間和,統(tǒng)計(jì)好所有請(qǐng)求次數(shù)與時(shí)間和后再計(jì)算平均時(shí)間。這樣所有分析好的數(shù)據(jù)就都在map里了,最后可針對(duì)這個(gè)map進(jìn)行excel導(dǎo)出,是不是很完美,哈哈。

          • 定義map,需要統(tǒng)計(jì)的字段用struct封裝。

          var?(
          ?result?map[string]*requestBody
          ?analysis?map[string]*requestBody
          )

          type?requestBody?struct?{
          ?count?int32
          ?query?string
          ?time?float64
          }
          • 因?yàn)槿罩疚募幸恍写硪粋€(gè)完整的日志,所以我們可以按行讀取日志,然后分析處理。

          func?openFile()?*os.File?{
          ?file,err?:=?os.Open("./request.log")
          ?if?err?!=?nil{
          ??log.Println("open?log?err:?",err)
          ?}
          ?return?file
          }

          func?logDeal(file?*os.File)??{
          ?//?按行讀取
          ?br?:=?bufio.NewReader(file)
          ?for{
          ??line,_,err?:=?br.ReadLine()
          ??//?file?read?complete
          ??if?err?==?io.EOF{
          ???log.Println("file?read?complete")
          ???return
          ??}
          ??//json?deal
          ??var?data?interface{}
          ??err?=?json.Unmarshal(line,&data)
          ??if?err?!=?nil{
          ???fmt.Errorf("json?marshal?error")
          ??}
          ??deal(data)
          ?}
          }
          • 按行讀取好數(shù)據(jù)后,開(kāi)始對(duì)每一條日志進(jìn)行分析,提取字段??梢允褂胓olang的json.Unmarshal,配合類型斷言,分析出每一個(gè)字段做處理。

          func?deal(data?interface{})??{
          ?var?request?string
          ?var?query?string
          ?var?time?float64
          ?value,ok?:=?data.(map[string]interface{})
          ?if?ok{
          ??for?k,v?:=?range?value{
          ???if?k?==?"httpRequest"{
          ????switch?v1?:=?v.(type)?{
          ????case?map[string]interface{}:
          ?????for?k1,v11?:=?range?v1{
          ??????if?k1?==?"request"{
          ???????switch?val?:=?v11.(type)?{
          ???????case?string:
          ????????request?=?val
          ????????//fmt.Println(request)
          ???????}
          ??????}
          ?????}
          ????}
          ???}
          ???if?k?==?"params"{
          ????switch?v1?:=?v.(type)?{
          ????case?map[string]interface{}:
          ?????for?k1,v11?:=?range?v1{
          ??????if?k1?==?"query"{
          ???????switch?val?:=?v11.(type)?{
          ???????case?string:
          ????????query?=?val
          ????????//fmt.Println(query)
          ???????}
          ??????}
          ?????}
          ????}
          ???}
          ???if?k?==?"timings"{
          ????switch?v1?:=?v.(type)?{
          ????case?map[string]interface{}:
          ?????for?k1,v11?:=?range?v1{
          ??????if?k1?==?"evalTotalTime"{
          ???????switch?val?:=?v11.(type)?{
          ???????case?float64:
          ????????time?=?val
          ???????//?fmt.Println(time)
          ???????}
          ??????}
          ?????}
          ????}
          ???}
          ??}
          ??b?:=?&requestBody{
          ???query:?query,
          ???time:?time,
          ??}
          ??if?_,o?:=?result[request];o{
          ???b.count?=?result[request].count?+?1
          ???b.time?=?b.time?+?result[request].time
          ???result[request]?=?b
          ??}else?{
          ???b.count?=?1
          ???result[request]?=?b
          ??}
          ?}
          }
          • 統(tǒng)計(jì)好所有的請(qǐng)求次數(shù)與請(qǐng)求時(shí)間和后,我們還需要進(jìn)一步處理,得到每次請(qǐng)求的平均時(shí)間。

          //analysis?data
          func?analysisBody()??{
          ?for?k,v?:=?range?result{
          ??req?:=?&requestBody{}
          ??req.time?=?v.time?/?float64(v.count)
          ??req.count?=?v.count
          ??req.query?=?v.query
          ??analysis[k]?=?req
          ?}
          }

          分析好了日志后,下面我們開(kāi)始導(dǎo)出excel。

          ?倒出excel文件

          這里使用的是excelize庫(kù)。首先進(jìn)行安裝:

          go?get?github.com/360EntSecGroup-Skylar/excelize

          excelize 詳細(xì)的文檔請(qǐng)點(diǎn)擊:https://xuri.me/excelize/zh-hans/。這里就不講解具體的使用方法了,直接上代碼了??梢酝扑]一個(gè)博客,我也是在這上面學(xué)習(xí)的。傳送門(mén)。這個(gè)庫(kù)還可以合并單元格,更多玩法,歡迎解鎖。

          導(dǎo)出代碼示例如下:

          type?cellValue?struct?{
          ?sheet?string
          ?cell?string
          ?value?string
          }
          //export?excel
          func?exportExcel()??{
          ?file?:=?excelize.NewFile()
          ?//insert?title
          ?cellValues?:=?make([]*cellValue,0)
          ?cellValues?=?append(cellValues,&cellValue{
          ??sheet:?"sheet1",
          ??cell:?"A1",
          ??value:?"request",
          ?},&cellValue{
          ??sheet:?"sheet1",
          ??cell:?"B1",
          ??value:?"count",
          ?},&cellValue{
          ??sheet:?"sheet1",
          ??cell:?"C1",
          ??value:?"query",
          ?},&cellValue{
          ??sheet:?"sheet1",
          ??cell:?"D1",
          ??value:?"avgTime",
          ?})
          ?index?:=?file.NewSheet("Sheet1")
          ?//?設(shè)置工作簿的默認(rèn)工作表
          ?file.SetActiveSheet(index)
          ?for?_,?cellValue?:=?range?cellValues?{
          ??file.SetCellValue(cellValue.sheet,?cellValue.cell,?cellValue.value)
          ?}
          ?//insert?data
          ?cnt?:=?1
          ?for?k,v?:=?range?analysis{
          ??cnt?=?cnt?+?1
          ??for?k1,v1?:=?range?cellValues{
          ???switch?k1?{
          ???case?0:
          ????v1.cell?=?fmt.Sprintf("A%d",cnt)
          ????v1.value?=?k
          ???case?1:
          ????v1.cell?=?fmt.Sprintf("B%d",cnt)
          ????v1.value?=?fmt.Sprintf("%d",v.count)
          ???case?2:
          ????v1.cell?=?fmt.Sprintf("C%d",cnt)
          ????v1.value?=?v.query
          ???case?3:
          ????v1.cell?=?fmt.Sprintf("D%d",cnt)
          ????v1.value?=?strconv.FormatFloat(v.time,'f',-1,64)
          ???}
          ??}
          ??for?_,vc?:=?range?cellValues{
          ???file.SetCellValue(vc.sheet,vc.cell,vc.value)
          ??}
          ?}

          ?//generate?file
          ?err?:=?file.SaveAs("./log.xlsx")
          ?if?err?!=?nil{
          ??fmt.Errorf("generate?excel?error")
          ?}
          }

          #?4. 結(jié)果展示

          怎么樣,還可以吧,我們可以看到請(qǐng)求次數(shù)與平均時(shí)間,一目了然。

          我也是第一次使用go進(jìn)行日志分析。總體來(lái)說(shuō)還是挺方便的。最主要是導(dǎo)出excel真的很方便。你學(xué)會(huì)了嗎?


          ? ?


          喜歡明哥文章的同學(xué)
          歡迎長(zhǎng)按下圖訂閱!

          ???

          瀏覽 93
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草人妻 | 韩国三级无码无遮床戏视频 | av先峰网婷婷五月天 | 九九精品成人 | 国产日韩二区 |