运维大神如何使用 Golang 日志监控应用程序

Posted 51reboot运维开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运维大神如何使用 Golang 日志监控应用程序相关的知识,希望对你有一定的参考价值。




2.27日分享介绍

1.Go 日志基础

2.Go 日志统一格式

  • JSON 格式的结构优势

  • 标准化 Golang 日志

3.Go 日志上下文

4.Go 日志对性能的影响

  • 不要在 Goroutine 中使用日志

  • 使用异步库

  • 使用严重等级管理日志

5.集中化 Go 日志

6.享受 Go 日志之旅


直播时间:2.27日21:00-22:00

文末添加小助手获取直播链接




你是如何使用 Golang 日志监控你的应用程序的呢?Golang 没有异常,只有错误。因此你的第一印象可能就是开发 Golang 日志策略并不是一件简单的事情。不支持异常事实上并不是什么问题,异常在很多编程语言中已经失去了其异常性:它们过于被滥用以至于它们的作用都被忽视了。


在进一步深入之前,我们首先会介绍 Golang 日志的基础,并讨论 Golang 日志标准、元数据意义、以及最小化 Golang 日志对性能的影响。通过日志,你可以追踪用户在你应用中的活动,快速识别你项目中失效的组件,并监控总体性能以及用户体验。


Go 日志基础


运维大神如何使用 Golang 日志监控应用程序使用 Golang “log” 库

Golang  给你提供了一个称为 “log” 的原生日志库。它的日志器完美适用于追踪简单的活动,例如通过使用可用的选项在错误信息之前添加一个时间戳。
下面是一个 Golang 中如何记录错误日志的简单例子:
package main

import (
    "fmt" 
    "errors"     "log"
)

func div(a, b int) (ret int, err error) 
    { if b == 0 {
    err = errors.New("division by zero"
    return
    }
    ret = a / b
    return
}
func main() {
    /* 定义局部变量 */ 
    a := 10
    b := 0
    /* 除法函数,除以 0 的时候会返回错误 */
    ret, err := div(a, b) 
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(ret)
}


如果你尝试除以0,你就会得到类似下面的结果:
2020/02/24 16:13:30 division by zero


为了快速测试一个 Golang 函数,你可以使用 go playground。为了确保日志总是能轻易访问,可以把 log 写在一个文件:

package main import (
    "log"
    "os"
)
func main() {
    // 按照所需读写权限创建文件
    f, err := os.OpenFile("filename", os.O_WRONLY|os.O_CREATE|os.O_APPEND,
0644)
    if err != nil {
    log.Fatal(err)
    }
    // 完成后延迟关闭,而不是习惯! defer f.Close()
    //设置日志输出到 f log.SetOutput(f)
    //测试用例
    log.Println("check to make sure it works")
}


可以找到 Golang 日志的完整指南,以及“log”库内可用函数的完整列表。现在你就可以记录它们的错误以及根本原因啦。另外,日志也可以帮你将活动流拼接在一起,查找需要修复的错误上下文,或者调查在你的系统中单个  请求如何影响其它应用层和 API。为了获得更好的日志效果,你首先需要在你的项目中使用尽可能多的上下文丰富你的 Golang 日志,并标准化你使用的格式。这就是 Golang 原生库能达到的极限。使用最广泛的库是 glog 和 logrus。必须承认还有很多好的库可以使用。如果你已经在使用支持 JSON  格式的库,你就不需要再换其它库了,后面我们会解释。



 Go 日志统一格式


运维大神如何使用 Golang 日志监控应用程序JSON 格式的结构优势

在一个项目或者多个微服务中结构化你的 Golang 日志可能是最困难的事情,但一旦完成就很轻松了。结构化你的日志能使机器可读。灵活性和层级是JSON 格式的核心,因此信息能够轻易被人类和机器解析以及处理。

下面是一个使用 Logrus/Logmatic.io 如何用 JSON 格式记录日志的例子:
package main import (
    log "github.com/Sirupsen/logrus" 
    "github.com/logmatic/logmatic-go"
)
func main() {
    // 使 用 JSONFormatter 
    log.SetFormatter(&logmatic.JSONFormatter{})
      // 使用 logrus 像往常那样记录事件
    log.WithFields(log.Fields{"string": "foo", "int": 1, "float": 1.1
}).Info("My first ssl event from golang")
}


会输出结果:
{
    "date":"2016-05-09T10:56:00+02:00",
    "float":1.1,
    "int":1, "level":"info",
    "message":"My first ssl event from golang", "String":"foo"
}



标准化 Golang  日志
同一个错误出现在你代码的不同部分,却以不同形式被记录下来是一件可耻的事情。下面是一个由于一  个变量错误导致无法确定 web 页面加载状态的例子。一个开发者日志格式是:
message: 'unknown error: cannot determine loading status from unknown error: missing or invalid arg value client'</span>


另一个人的格式却是:
unknown error: cannot determine loading status - invalid client</span>


强制日志标准化的一个好的解决办法是在你的代码和日志库之间创建一个接口。这个标准化接口会包括  所有你想添加到你日志中的可能行为的预定义日志消息。这么做可以防止出现不符合你想要的标准格式  的自定义日志信息。这么做也便于日志调查。

由于日志格式都被统一处理,使它们保持更新也变得更加简单。如果出现了一种新的错误类型,它只需要被添加到一个接口,这样每个组员都会使用完全相同的信息。

最常使用的简单例子就是在Golang 日志信息前面添加日志器名称和id。你的代码然后就会发送“事件” 到你的标准化接口,它会继续讲它们转化为Golang 日志消息。
// 主要部分,我们会在这里定义所有消息。
// Event 结构体很简单。为了当所有信息都被记录时能检索它们,
// 我们维护了一个 Id
var (
    invalidArgMessage = Event{1, "Invalid arg: %s"}
    invalidArgValueMessage = Event{2, "Invalid arg value: %s => %v"}
    missingArgMessage = Event{3, "Missing arg: %s"}
)

// 在我们应用程序中可以使用的所有日志事件
func (l *Logger)InvalidArg(name string) 
  { l.entry.Errorf(invalidArgMessage.toString(), name)
}
func (l *Logger)InvalidArgValue(name string, value interface{}) 
  { l.entry.WithField("arg." + name,
value).Errorf(invalidArgValueMessage.toString(), name, value)
}
func (l *Logger)MissingArg(name string) 
  { l.entry.Errorf(missingArgMessage.toString(), name)
}


因此如果我们使用前面例子中无效的参数值,我们就会得到相似的日志信息:

time="2017-02-24T23:12:31+01:00" level=error msg="LoadPageLogger00003 - Missing
arg: client - cannot determine loading status" arg.client=<nil>
logger.name=LoadPageLogger


JSON 格式如下:

{"arg.client":null,"level":"error","logger.name":"LoadPageLogger","msg":"LoadPag
eLogger00003 - Missing arg: client - cannot determine loading status",
"time":"2017-02-24T23:14:28+01:00"}



Go日志上下文


现在 Golang 日志已经按照特定结构和标准格式记录,时间会决定需要添加哪些上下文以及相关信息。为了能从你的日志中抽取信息,例如追踪一个用户活动或者工作流,上下文和元数据的顺序非常重要。

例如在 logrus 库中可以按照下面这样使用 JSON 格式添加 hostname、appname 和 session 参数:
// 对于元数据,通常做法是通过复用来重用日志语句中的字段。
  contextualizedLog :=
  log.WithFields(log.Fields{ "hostname":
    "staging-1",
    "appname": "foo-app",
    "session": "1ce3f6v"
  })


元数据可以视为 javascript 片段。 为了更好地说明它们有多么重要,让我们看看几个 Golang 微服务中元数据的使用。 你会清楚地看到是怎么在你的应用程序中跟踪用户的。 这是因为你不仅需要知道一个错  误发生了,还要知道是哪个实例以及什么模式导致了错误。 假设我们有两个按顺序调用的微服务。 上下  文信息保存在头部(header)中传输:


func helloMicroService1(w http.ResponseWriter, r *http.Request) { client := &http.Client{}
// 该服务负责接收所有到来的用户请求
// 我们会检查是否是一个新的会话还是已有会话的另一次调用
session := r.Header.Get("x-session")
if ( session == "") {session = generateSessionId()
// 为新会话记录日志
}
// 每个请求的 Track Id 都是唯一的,因此我们会为每个会话生成一个
track := generateTrackId()
// 调用你的第二个微服务,添加 session/track
reqService2, _ := http.NewRequest("GET", "http://localhost:8082/", nil
reqService2.Header.Add("x-session", session)reqService2.Header.Add("x-track", track) resService2, _ := client.Do(reqService2)
….


运维大神如何使用 Golang 日志监控应用程序

......




运维大神如何使用 Golang 日志监控应用程序



51Reboot 最新 go 课程第5期开课了


51Reboot 最新 k8s 课程第3期,python自动化运维进阶课程第十期正在火热招生中


详情扫码咨询

运维大神如何使用 Golang 日志监控应用程序


运维大神如何使用 Golang 日志监控应用程序

https://ke.qq.com/course/803805?taid=5266841086477277&tuin=31589b0e


内容如下:


第一阶段:Golang 语法入门

  • Golang 常用开发工具介绍

  • Golang 语法熟悉

  • Golang 处理命令行参数

  • Golang 实现用 GIF 动画展示程序并发架构


第二阶段:Golang 微服务实战

  • 实现一个简单的基于 Telnet 聊天室服务

  • 基于 Socket 手写一个简单的 HTTP 服务器

  • Socket 版 echo 协议服务器


第三阶段:Golang 高并发实战

  • 并发的 Clock 服务

  • 并发的 Echo 服务

  • 并发的 Web 爬虫

  • 聊天服务


第四阶段:分布式高可用实战

  • 分布式高可用监控 OpenFalcon 架构讲解

  • 通过 cgo 调用 C 代码

  • 深度解析 Golang Net/RPC 框架

  • 用户自定义监控项

  • Go 写入 ElasticSearch


第五阶段:运维监控系统实战

  • 手写监控系统

  • 完成监控 Agent 的数据上报逻辑:将本端的数据进行采集,然后将数据交个网络模块,再由网络模块将数据传输给 server 端。



https://ke.qq.com/course/450881?quicklink=1


内容如下:

Docker V1 Summary

Warm UP

  • 如何快速安装 LNMP 环境?

  • 如何快速做环境需要迁移?

  • 如何快速部署百台千台 LNMP 环境?

  • 开发、测试、运行环境如何统一?

  • 如何提高服务器资源利用率?如果服务混部,如何解决服务依赖各系统组件版本冲突问题?


Docker Basic 20%

  • Installing Docker

  • Docker Client,Server and Daemon

  • Containers lifecycle

  • Docker layers and caching

  • Docker registry

  • Dockerfile

  • Docker Building

  • Expose and binding ports

通过以上学习,学员可以从0到1了解 Docker,包括 Docker 的架构、Docker 的运行机制、生命周期以及 Docker 镜像等,从安装到运行,以及日常工作中常用的基本的操作,可以达到 Docker 入门级别。


Docker Digging Deeper 30%

  • Docker Compose

  • Docker Storage Driver

  • Docker Application Data Managerment

  • Docker Networking model

  • Docker Cgroups and Namespace

  • Docker Security

  • Docker Garbage Collection

Docker LXCFS 通过以上深入学习,学员们可以深度掌握 Docker 技术内幕,比如:Storage Driver、网络模型、隔离和资源限制以及安全等,这会对以后工作中,解决相关问题时打下非常好的基础。


Docker CI/CD 25%

  • Docker Harbor

  • Jeckins

  • Gitlab

  • Project exercise with CI/CD

通过对上述的学习, 学员们可以了解到如何在企业内部应用 Docker 技术,通过做一个 CI/CD 的 Demo,让学员们能够掌握什么是 CI/CD,Docker 技术在企业的落地也就是从这里开始的,所以,本章节的重要程度不言而喻,掌握了它,就可以达到企业级 Docker 应用工程师级别。


Docker For Ops 25%

  • Docker Monitors

  • Debugging Running containers

通过对上述的学习,以及在学习过程中一起踩过的坑,学员们可以进一步掌握Docker技术运用技能,当企业的业务无论是已经进行了容器化还是在容器化的路上,对于 Docker 容器化运维技术和调试技术的要求也是随之更加强烈,所以,掌握了它,才能说真正的达到了docker工程师级别。

  • 某业务采用 nginx 作为服务器,在申请容器时,配置是两核 CPU,ngxin 并发配置:nginx worker_processes=auto,但是运行过程中应用的是宿主机的全部 CPU 核数,为什么?如何处理?

reference


Kubernetes V1 Summary
Kubernetes Introduction

  • What is Kubernetes?

  • Kubernetes Basic Architecture

  • Master Components

- etcd        
- kube­apiserver       
- kube­scheduler        
- kube­Controller­Manager
  • Node Components

- kubelet        
- kube­proxy        
- Container Runtime
  • Fast Install K8S Cluster

  • kubectl

通过上面的学习,可以了解到为什么需要使用 Kubernetes ?结合 Kubernetes 的架构,学习到各核心组件的工作机制,包括:Master Components 和 Node Components;最后让我们快速安装一个 K8S Cluster,达到入门级效果,为下一步深入学习 K8S 奠定基础。

Kubernetes Concepts and Operations

  • k8s Node and labels

  • The smallest deployable object pod

  • Defining a Deployment

  • Defining a Statefulset

因为 Kubernetes 是一套容器编排、管理和调度系统,那么通过上面的学习,可以掌握 Kubernetes 在的内部是如何管理和调度容器的;另外,为什么要把容器封装到 pod 里?为什么需要 Deployment 和Statefulset?Deployment 和 Statefulset 有什么区别?分别应用于哪种场景?至此,对于 K8S 已经具备了一定的认识,下一步是如何与服务建立联系,并且对外发布服务。


PERSISTENCE & STORAGE

  • Managing stateful applications

  • HostPath

  • Persistent volume

  • Persistent volume claim

  • Dynamic provisioning

  • Managing configurations

  • Managing secrets

通过上述学习, 学员可以掌握 k8s 为了支持有状态服务以及在数据存储方面所做的技术实现,本阶段我们将结合开源存储系统 Ceph 进行项目练习;让学员可以深刻掌握 k8s 在数据存储方面的技术实践。


Kubernetes Service、 Load Balancing and Networking

  • Services

  • kube­proxy

  • Endpoints

  • Ingress

本章节主要讲解了 Kubernetes Service、LB 和 Networking,其目的就是为了让大家能够快速的进入自己的角色,因为我们前面做的一切工作,都是为了让我们的服务能够顺利的对外发布,那么至此,我们的第一目标达到了;但是,距离达到企业生产线上的服务要求标准还差的很远,这也是我们下一步要学习的;留下思考:企业生产线上的服务运行时要求标准都有哪些?该如何适配?提示:为了能够在企业对k8s技术进行落地,需要从如下几个方面进行考量,包括 Overlay 网络能否满足需求、数据存储能否满足需求、业务部署在 k8s 平台之后,如何发布更新?如何保障服务稳定性?业务日志如何采集和管理?监控能否做到位,k8s 平台自身的可用性和稳定性如何保证等等


Cluster Network

  • ovs

  • flannel

  • contiv

  • macVlan

  • calico

通过上述的学习,学员可以掌握几种网络技术的工作原理,以及 CNI 的工作原理,并根据企业内部的技术积累和当前网络拓扑情况,应该如何做技术选型。


DEPLOYMENT

  • Rolling updates

  • Deployment history & rollbacks

  • Selectors and labelsCanary deployments

  • Blue­green deployments

通过上述学习, 学员可以掌握k8s在支持部署方面所做的技术实现,本章节可以让学员们了解多种部署模式;方便日后在企业中可以根据企业内部情况进行部署技术的选型。

Logging architecture

  • sidecar container

  • filebeat logs collection

业务迁移到 k8s 平台之后,业务的日志采集和处理是一个非常关键和棘手的问题,本章节通过两种比较常用的日志收集手段,向学员们展示如何做日志收集,以及采集过程中需要注意哪些问题。


ADVANCED SCHEDULING

  • Scheduler architecture

  • Predicated and priorities

  • Attaching pods to nodes

  • Node affinity/anti­affinity

  • Pod affinity/anti­affinity

  • Taints and tolerations

  • Custom scheduler

本章节会介绍在企业中常用的高级调度策略,比如如何修改预选,如何指定 node 调度 pod,如何打散 pod 调度,如何创建独立集群,以及如何自定义调度器等等,掌握这些技术之后,基本满足企业级容器调度要求了;至此,为了让业务迁入k8s平台,功能上已经达到了满足。


K8S For OPS

  • Authentication

  • Authorization

  • Resource metrics API

  • Custom resource metrics

  • Api­server access limits

  • kubectl access limits

  • RBAC

  • Admission controllers

  • Security contexts

  • Pod Security PoliciesDebugging pods

  • Monitor

K8S For OPS 放到了最后,说明其重要性,本章节将重点介绍如何运维 k8s 集群,如何调试业务容器和 debug 集群,如何限制 apiserver 的访问,监控的重要性更不言而喻了。







以上是关于运维大神如何使用 Golang 日志监控应用程序的主要内容,如果未能解决你的问题,请参考以下文章

AIOps大神之路

运维 | 智能运维(AiOps)之日志监控及日志分析系统分析

数据中心里如何做好日志监控

线上bug日志监控,主动运维平台搭建

运维开发实践——基于Sentry搭建错误日志监控系统

运维道中道之“Shell脚本日志关键字监控+告警”