Go微服務: 日志系統ELK的應用

概述

  • 基于前文,我們已經了解并搭建完成ELK的所有環境了,現在我們來結合應用程序來使用ELK
  • 參考前文:https://active.blog.csdn.net/article/details/138898538

封裝日志模塊

  • 在通用工具模塊: gitee.com/go-micro-services/common 這個包是通用的工具包
  • 新增 zap.go
    package commonimport ("fmt""os""path/filepath""go.uber.org/zap""go.uber.org/zap/zapcore""gopkg.in/natefinch/lumberjack.v2"
    )// MyType 是我們想要提供的類型
    type ZapLogger struct {logger *zap.SugaredLogger
    }// NewMyType 是一個構造函數,用于創建 MyType 的新實例
    func NewZapLogger(filePath string, FilePerms int) *ZapLogger {log, _ := ZapLoggerInit(filePath, FilePerms)return &ZapLogger{logger: log}
    }func (zl *ZapLogger) Debug(args ...interface{}) {zl.logger.Debug(args)
    }func (zl *ZapLogger) Debugf(template string, args ...interface{}) {zl.logger.Debugf(template, args...)
    }func (zl *ZapLogger) Info(args ...interface{}) {zl.logger.Info(args...)
    }func (zl *ZapLogger) Infof(template string, args ...interface{}) {zl.logger.Infof(template, args...)
    }func (zl *ZapLogger) Warn(args ...interface{}) {zl.logger.Warn(args...)
    }func (zl *ZapLogger) Warnf(template string, args ...interface{}) {zl.logger.Warnf(template, args...)
    }func (zl *ZapLogger) Error(args ...interface{}) {zl.logger.Error(args...)
    }func (zl *ZapLogger) Errorf(template string, args ...interface{}) {zl.logger.Errorf(template, args...)
    }func (zl *ZapLogger) DPanic(args ...interface{}) {zl.logger.DPanic(args...)
    }func (zl *ZapLogger) DPanicf(template string, args ...interface{}) {zl.logger.DPanicf(template, args...)
    }func (zl *ZapLogger) Panic(args ...interface{}) {zl.logger.Panic(args...)
    }func (zl *ZapLogger) Panicf(template string, args ...interface{}) {zl.logger.Panicf(template, args...)
    }func (zl *ZapLogger) Fatal(args ...interface{}) {zl.logger.Fatal(args...)
    }func (zl *ZapLogger) Fatalf(template string, args ...interface{}) {zl.logger.Fatalf(template, args...)
    }// 這個供外部調用
    func ZapLoggerInit(filePath string, FilePerms int) (*zap.SugaredLogger, error) {fileName, fileErr := createFileWithPerms(filePath, os.FileMode(FilePerms))if fileErr != nil {// 使用 %v 來打印 error 類型的變量fmt.Printf("Error: %v\n", fileErr)return nil, fileErr}fmt.Printf("日志文件路徑: %s\n", fileName)syncWriter := zapcore.AddSync(&lumberjack.Logger{Filename: fileName, //文件名稱MaxSize:  521,      // MB// MaxAge:     0,MaxBackups: 0, //最大備份LocalTime:  true,Compress:   true, //是否啟用壓縮})// 編碼encoder := zap.NewProductionEncoderConfig()// 時間格式encoder.EncodeTime = zapcore.ISO8601TimeEncodercore := zapcore.NewCore(// 編碼器zapcore.NewJSONEncoder(encoder),syncWriter,zap.NewAtomicLevelAt(zap.DebugLevel))log := zap.New(core,zap.AddCaller(),zap.AddCallerSkip(1))return log.Sugar(), nil
    }// 創建一個多層目錄下的文件,并設置權限, 如果文件已存在,則返回文件的路徑;如果不存在,則創建并返回文件路徑
    func createFileWithPerms(filePath string, perms os.FileMode) (string, error) {// 檢查文件或目錄是否存在fileInfo, err := os.Lstat(filePath)if err == nil {// 文件或目錄已存在if fileInfo.IsDir() {// 如果已存在的是目錄,返回錯誤return "", fmt.Errorf("無法創建文件 '%s',因為該路徑已存在且是一個目錄", filePath)}// 如果已存在的是文件,則返回文件路徑return filePath, nil}if !os.IsNotExist(err) {// 如果發生其他錯誤(如權限問題),則返回錯誤return "", fmt.Errorf("檢查文件 '%s' 時發生錯誤: %v", filePath, err)}// 創建多級目錄err = os.MkdirAll(filepath.Dir(filePath), os.ModePerm) // 使用 os.ModePerm 允許所有權限,但文件權限會由下面的 os.Create 設置if err != nil {return "", fmt.Errorf("無法創建目錄 '%s': %v", filepath.Dir(filePath), err)}// 創建文件file, err := os.Create(filePath)if err != nil {return "", fmt.Errorf("無法創建文件 '%s': %v", filePath, err)}// 關閉文件,因為我們只需要路徑defer file.Close()// 設置文件權限err = file.Chmod(perms)if err != nil {return "", fmt.Errorf("無法設置文件 '%s' 的權限: %v", filePath, err)}// 返回新創建文件的路徑return filePath, nil
    }
    
  • 上面這個模塊,封裝了打印日志的各種方法,基于其定義可以看出是基于實例的
  • 也就是說,不是靜態的方法,而是可以 new 出很多實例的,這樣可以讓我們使用場景更加豐富
  • 代碼倉庫:https://gitee.com/go-micro-services/common

網關和服務應用程序準備


1 )概述
  • ELK簡單來說,一般部署在我們的網關上,還是和之前一樣,基于 gin 框架
  • 如果部署在各個微服務中,那環節就比較麻煩,而且資源耗費較多
  • 在我們的網關上來使用,還用之前的場景,基于網關上的某一個api來獲取購物車中的數據
  • 例如:
    • /api/findAllTestElk1?user_id=1 基于這個路由,使用默認日志實例來輸出, 正確日志
    • /api/findAllTestElk1?user_id=x 同上,觸發錯誤日志
    • /api/findAllTestElk2?user_id=1 基于這個路由,自定義新的日志實例來輸出
    • /api/findAllTestElk2?user_id=x 同上,觸發錯誤日志
  • 基于以上,可以在不同模塊實例化不同的日志文件

2 )utils包

  • utils/log.go

    package utilsimport ("gitee.com/go-micro-services/common"
    )// 通用配置
    var ZapLogger *common.ZapLogger// 日志默認設置
    func initLog() {ZapLogger = common.NewZapLogger("logs/app.log", 0777) // 這里兩個參數可以配置到 conf/app.ini 中
    }
    
    • 這里使用 common 工具包,來實例化一個默認的日志實例
  • utils/common.go

    func init() {initLog() // 添加這個
    }
    
    • 可見,在 init 函數中添加 initLog 函數

3 ) 定義路由

package routersimport ("gitee.com/go-micro-services/api/controllers/api""github.com/gin-gonic/gin"
)func RoutersInit(r *gin.Engine) {rr := r.Group("/api"){rr.GET("/findAll", api.ApiController{}.FindAll)rr.GET("/findAllTestElk1", api.Log1Controller{}.FindAllTestElk)rr.GET("/findAllTestElk2", api.Log2Controller{}.FindAllTestElk)}
}
  • 可見這里定義了三個路由,我們主要關注后面兩個
  • 下面來看對應的控制器

4 )控制器

  • controllers/api/log1.go

    package apiimport ("context""fmt""strconv""gitee.com/go-micro-services/api/utils"cart "gitee.com/go-micro-services/cart/proto/cart""github.com/gin-gonic/gin""github.com/prometheus/common/log"
    )type Log1Controller struct{}// 這個方法用于測試ELK
    func (con Log1Controller) FindAllTestElk(c *gin.Context) {log.Info("接受到 /api/findAllTestElk1 訪問請求")// 1. 獲取參數user_id_str := c.Query("user_id")userId, err := strconv.ParseInt(user_id_str, 10, 64)if err != nil {utils.ZapLogger.Error("參數異常")c.JSON(200, gin.H{"message": "參數異常","success": false,})return}fmt.Println(userId)// 2. rpc 遠程調用:獲取購物車所有商品cartClient := cart.NewCartService(utils.CartServices, utils.SrvClient)cartAll, err := cartClient.GetAll(context.TODO(), &cart.CartFindAll{UserId: userId})utils.ZapLogger.Info(cartAll)fmt.Println("-----")c.JSON(200, gin.H{"data":    cartAll,"success": true,})
    }
    
  • controllers/api/log2.go

    package apiimport ("context""fmt""strconv""gitee.com/go-micro-services/api/utils"cart "gitee.com/go-micro-services/cart/proto/cart""gitee.com/go-micro-services/common""github.com/gin-gonic/gin""github.com/prometheus/common/log"
    )type Log2Controller struct{}// 通用配置
    var ZapLogger *common.ZapLoggerfunc init() {ZapLogger = common.NewZapLogger("logs/app2.log", 0777) // 這里相關參數可以配置到 conf/app.ini 中
    }// 這個方法用于測試ELK
    func (con Log2Controller) FindAllTestElk(c *gin.Context) {log.Info("接受到 /api/findAllTestElk2 訪問請求")// 1. 獲取參數user_id_str := c.Query("user_id")userId, err := strconv.ParseInt(user_id_str, 10, 64)if err != nil {ZapLogger.Error("參數異常")c.JSON(200, gin.H{"message": "參數異常","success": false,})return}fmt.Println(userId)// 2. rpc 遠程調用:獲取購物車所有商品cartClient := cart.NewCartService(utils.CartServices, utils.SrvClient)cartAll, err := cartClient.GetAll(context.TODO(), &cart.CartFindAll{UserId: userId})ZapLogger.Info(cartAll)fmt.Println("-----")c.JSON(200, gin.H{"data":    cartAll,"success": true,})
    }
    
  • 上面兩個控制器的內容,基本一致,我們的目的是用來測試不同的日志實例的測試

    • 第一個控制器使用的是默認初始化時的日志對象
    • 第二個控制器使用的是重新初始化后的日志實例,這樣我們可以自定義不同的日志生成路徑
  • 代碼倉庫

    • 網關: https://gitee.com/go-micro-services/api
    • 購物車服務: https://gitee.com/go-micro-services/cart

5 )啟動網關和購物車服務

  • 可見,兩個服務已經啟動起來了

下載和運行 FileBeat 程序

  • 訪問:https://www.elastic.co/cn/downloads/past-releases/filebeat-7-9-3/
  • 注意:這里的版本要和之前ELK環境搭建時的版本對應
  • 選擇合適的版本,在服務器要選擇服務器版本,這里我選擇Mac版本來測試
  • 下載完成后,里面有很多配置好的文件,我們主要關注兩個: 二進制文件 filebeatfilebeat.yml
  • 將這兩個文件拷貝進入網關項目
  • 編輯 filebeat.yml
    # 輸入
    filebeat.inputs:- type: logenabled: truepaths:- ./logs/*.log
    #輸出
    output.logstash:hosts: ["localhost:5044"]
    
  • 這里,可以配置不同的文件來區分各個部署環境,因為環境不同,參數也不同
  • 也可以使用環境變量,部署時進行注入,我這里只是做了一個演示
  • 啟動命令 $ ./filebeat -e -c ./filebeat.yml
    • -e: 啟動在終端輸出采集信息
    • -c: 指定yml啟動配置文件
  • 當然這些個啟動命令,后期也可以在Dockerfile, DockerCompose 或 K8s中定義,不再贅述

登錄并配置 Kibana 來查看日志


1 ) 概述

  • 如果是本機搭建的,訪問: http://localhost:5601
    • 這里的 5601 就是之前搭建ELK時暴露出來的
  • 基于前文配置的用戶名和密碼進行登錄

2 ) 登錄之后,點擊右側的 Discover

3 ) 創建和配置索引

4 )回到 Discover 查看日志

截止目前為止,所有ELK環境已經全部打通 ~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/14662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/14662.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/14662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CTFHUB技能樹——SSRF(三)

目錄 URL Bypass 數字IP Bypass 302跳轉 Bypass DNS重綁定 Bypass SSRF繞過方法: (1) http://abc.com127.0.0.1 (2)添加端口號 http://127.0.0.1:8080 (3)短地址 htt…

限制U盤使用:企業數據安全的軟件解決方案

在當今數字化辦公環境中,U盤作為一種便捷的數據傳輸工具,其使用在企業內部非常普遍。然而,U盤的不當使用也給企業數據安全帶來了巨大風險。為了防止數據泄露和病毒傳播,企業需要采取有效的軟件解決方案來限制U盤的使用。本文將探討…

linux使用dockerCompose腳本化部署鏡像

1.根據實際修改docker-compose.yml文件: version: 3.5 services:#mysql數據庫腳本mysql:image: 鏡像名:版本 #需要查看本地鏡像進行填寫。同下container_name: mysql #容器名,同下restart: alwaysports:- 3306:3306 #第一個3306為主機…

Java中解決跨域的幾種方法

一、 什么是跨域(同源策略) 同源的定義:如果兩個頁面的協議,端口(如果有指定)和主機都相同,則兩個頁面具有相同的源 1,用戶在瀏覽器輸入的URL中包含的協議、域名、端口都完全相同。如果有一項不同&#xf…

【python005】python批量、動態調參請求接口(已更新)

1.熟悉、梳理、總結項目研發實戰中的Python開發日常使用中的問題。隨著版本更新,做了一些變動,如商業化限制,取消一些語法等。 2.歡迎點贊、關注、批評、指正,互三走起來,小手動起來! 文章目錄 1.背景介紹2.單次接口請求總結代碼片3.批量循環接口請求總結代碼片4.持久化`…

機器人流程自動化與低代碼流程自動化:技術革新的雙重驅動

在數字化時代的浪潮中,企業對于高效、智能的工作流程的需求日益增強。在這一背景下,機器人流程自動化(RPA)和低代碼流程自動化(Low-Code Automation)應運而生,成為推動企業數字化轉型的重要力量…

docker容器安裝mysql

linux: centOS-7 hadoop: 3.3.6 前置章節: (圖文并茂)基于CentOS-7搭建hadoop3.3.6大數據集群-CSDN博客 可選:zookeeper安裝教程-CSDN博客 1.安裝docker 1.1 添加docker的repo源 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/…

一個月速刷leetcodeHOT100 day08 兩道DP題 一道子串

和為k的子數組 中等 提示 給你一個整數數組 nums 和一個整數 k ,請你統計并返回 該數組中和為 k 的子數組的個數 。 子數組是數組中元素的連續非空序列。 示例 1: **輸入:**nums [1,1,1], k 2 **輸出:**2 示例 2: *…

集合、Collection接口特點和常用方法

1、集合介紹 對于保存多個數據使用的是數組,那么數組有不足的地方。比如, 長度開始時必須指定,而且一旦制定,不能更改。 保存的必須為同一類型的元素。 使用數組進行增加/刪除元素的示意代碼,也就是比較麻煩。 為…

一種簡單實用的ollvm反混淆的方案與源碼

我是一名從事反欺詐&風控&設備指紋相關的工作,最近對ollvm的如何逆向的問題進行了學習與思考。 ollvm是一個開源免費的so混淆工具,對于逆向的小白來說簡直是災難性的存在。 這個例子是超簡單,我想每個人都可以學會跟掌握,…

RustGUI學習(iced/iced_aw)之擴展小部件(二十五):如何使用tab部件來創建tab多頁面切換?

前言 本專欄是學習Rust的GUI庫iced的合集,將介紹iced涉及的各個小部件分別介紹,最后會匯總為一個總的程序。 iced是RustGUI中比較強大的一個,目前處于發展中(即版本可能會改變),本專欄基于版本0.12.1. 概述 這是本專欄的第二十五篇,主要講述tab頁面切換部件的使用,會結…

[linux] bash中的單引號(‘)和雙引號(“)

在命令行中,單引號()和雙引號(")在某些情況下會有不同的效果,尤其是在涉及bash變量和特殊字符的解析時。在你給出的兩個命令中: ps -ef|grep "tokenize"|grep -v grep|awk {print $2} 和 ps -ef|grep "tokenize"…

PCL點云邊界提取——源碼解析

文章目錄 一、概述二、PCL邊緣檢測源碼定位過程1、初始化2、檢查輸入點云是否稠密3、迭代處理每個點4、輸出三、修改后的過程調用一、概述 在PCL中集成了一個非常經典的點云邊緣檢測算法,這個算法也在 PCL點云邊界提取這篇博客中講解了。該文章只介紹了AC算法的原理及接口調用…

hook中useContext到底怎么用

語法: somecontext createContext(defaultValue); 作用: 避免了組件嵌套太深, 頂層變量層層傳遞的麻煩. 如何消費頂層數據 第一步: 用createContext聲明一個context上下文變量 import { createContext } from react;export const GlobalContext createContext({} as any);…

面試問題小結

說說你的項目,從里面學到啥了(隨便說) CAS 線程池 的各個方面 線程咋創建(4種方式) 說一下聚集索引和非聚集索引 50w男 50w女 ,在B樹中咋存儲的(類似下面的圖,變通一下就行了&a…

本是夢中人,常作花下客。心中自往來,知我有幾個。

我們總是喜歡拿“順其自然”來敷衍人生道路上的荊棘坎坷,卻很少承認,真正的順其自然, 其實是竭盡所能之后的不強求, 而非兩手一攤的不作為。 一花凋零荒蕪不了整個春天, 一次挫折也荒廢不了整個人生。 多年后&#x…

近臨算法(個人總結版)

背景 近鄰算法(Nearest Neighbor Algorithm)是一種基本但非常有效的分類和回歸方法。最早由Fix和Hodges在1951年提出,經過幾十年的發展和改進,已成為數據挖掘、模式識別和機器學習領域的重要工具。近鄰算法基于相似性原則&#x…

通過el-tree自定義渲染網頁版工作目錄,實現鼠標懸浮顯示完整名稱、用icon區分文件和文件夾等需求

目錄 一、通過el-tree自定義渲染網頁版工作目錄 1.1、需求介紹 1.2、使用el-tree生成文檔目錄 1.2.1、官方基礎用法 ①效果 ②代碼: 1.2.2、自定義文檔目錄(實現鼠標懸浮顯示完整名稱、用icon區分文件和文件夾) ①效果(直接效…

find 幾招在 Linux 中高效地查找目錄

1. 介紹 在 Linux 操作系統中,查找目錄是一項常見的任務。無論是系統管理員還是普通用戶,都可能需要查找特定的目錄以執行各種操作,如導航文件系統、備份數據、刪除文件等。Linux 提供了多種命令和工具來幫助我們在文件系統中快速找到目標目…

淺談后端整合Springboot框架后操作基礎配置

boot基礎配置 現在不訪問端口8080 可以嗎 我們在默認啟動的時候訪問的是端口號8080 基于屬性配置的 現在boot整合導致Tomcat服務器的配置文件沒了 我們怎么去修改Tomcat服務器的配置信息呢 配置文件中的配置信息是很多很多的... 復制工程 保留工程的基礎結構 抹掉原始…