运维大神如何使用 Golang 日志监控应用程序
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 日志对性能的影响。通过日志,你可以追踪用户在你应用中的活动,快速识别你项目中失效的组件,并监控总体性能以及用户体验。
使用 Golang “log” 库
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 / breturn
}
func main() {
/* 定义局部变量 */a := 10
b := 0
/* 除法函数,除以 0 的时候会返回错误 */
ret, err := div(a, b)if err != nil {
log.Fatal(err)
}
fmt.Println(ret)
}
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 格式的库,你就不需要再换其它库了,后面我们会解释。
JSON 格式的结构优势
package main
import (
log "github.com/Sirupsen/logrus""github.com/logmatic/logmatic-go"
)
func main() {
// 使 用 JSONFormatterlog.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"
}
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>
// 主要部分,我们会在这里定义所有消息。
// 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"}
现在 Golang 日志已经按照特定结构和标准格式记录,时间会决定需要添加哪些上下文以及相关信息。为了能从你的日志中抽取信息,例如追踪一个用户活动或者工作流,上下文和元数据的顺序非常重要。
// 对于元数据,通常做法是通过复用来重用日志语句中的字段。
contextualizedLog :=
log.WithFields(log.Fields{ "hostname":
"staging-1",
"appname": "foo-app",
"session": "1ce3f6v"
})
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)
….
......
51Reboot 最新 go 课程第5期开课了
51Reboot 最新 k8s 课程第3期,python自动化运维进阶课程第十期正在火热招生中
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
Node Components
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
kubeproxy
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
Bluegreen deployments
通过上述学习, 学员可以掌握k8s在支持部署方面所做的技术实现,本章节可以让学员们了解多种部署模式;方便日后在企业中可以根据企业内部情况进行部署技术的选型。
Logging architecture
sidecar container
filebeat logs collection
业务迁移到 k8s 平台之后,业务的日志采集和处理是一个非常关键和棘手的问题,本章节通过两种比较常用的日志收集手段,向学员们展示如何做日志收集,以及采集过程中需要注意哪些问题。
ADVANCED SCHEDULING
Scheduler architecture
Predicated and priorities
Attaching pods to nodes
Node affinity/antiaffinity
Pod affinity/antiaffinity
Taints and tolerations
Custom scheduler
本章节会介绍在企业中常用的高级调度策略,比如如何修改预选,如何指定 node 调度 pod,如何打散 pod 调度,如何创建独立集群,以及如何自定义调度器等等,掌握这些技术之后,基本满足企业级容器调度要求了;至此,为了让业务迁入k8s平台,功能上已经达到了满足。
K8S For OPS
Authentication
Authorization
Resource metrics API
Custom resource metrics
Apiserver access limits
kubectl access limits
RBAC
Admission controllers
Security contexts
Pod Security PoliciesDebugging pods
Monitor
K8S For OPS 放到了最后,说明其重要性,本章节将重点介绍如何运维 k8s 集群,如何调试业务容器和 debug 集群,如何限制 apiserver 的访问,监控的重要性更不言而喻了。