SGAME的日志系统

本文详细介绍了SGAME框架的日志系统,该系统基于slog库,支持本地和网络日志。本地日志包括DEBUG,INFO,ERR,FATAL四个级别,支持日志滚动和多粒度时间。网络日志通过UDP发送,支持多种发送方式,便于审计和统计。文中给出了具体的API使用示例。" 104674956,8180963,CodeCraft-20比赛解析:AC题目详解,"['编程竞赛', '算法题解', '数学应用', '字符串算法']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

综述

SGAME框架所使用的日志系统基于一个小的日志库slog,具体细节可以参考https://github.com/nmsoccer/slog 其安装也很简单,会在/usr/local/lib下生成一个slog.a静态库(主要免去到目标机器时各种部署动态库的麻烦,而且便于调试). slog有一个slog.go作为GO的API,在框架里已经包含

 

源码

SGAME的日志目录位于sgame/lib/log,内容如下

sgame/lib/log/
|-- api.go
`-- slog.go
  • slog.go: 是slog项目本身提供的GO接口,我们将其包含进来
  • api.go: 是基于slog与SGAME框架本身的封装层,框架实际使用的是api.go里的函数 

类别

SGAME框架主要提供两类日志:

  • 本地文件日志,方便记录进程运行时的各种事件
  • 网络传输日志,因为游戏经常会有经分审计等需要,而且很多重要的功能节点也需要专门的信息保存,所以可以通过网络日志将重要信息发送到对端的UDP服务器用于保存和统计。因为是基于简单的UDP文本传输,接收端的开发也会很简单

 

本地日志

本地日志支持以下功能

  • 日志分级
    SGAME框架主要分为DEBUG,INFO,ERR,FATAL等四个级别。而且支持在进程运行时动态调整打印级别
  • 日志滚动
    SGAME框架支持日志文件的滚动,同时支持进程运行时的数目动态修改
  • 时间粒度
    支持秒,毫秒,微秒和纳秒四个粒度的时间,同时也支持进程运行时动态调整
  • 协程支持
    框架本身使用了多协程处理,所以支持多协程的日志打印

API

  • 打开日志句柄
/*Open a Log handler
* @filt_level:refer LOG_LV_XX. only print log above filt-level
* @log_degree:refer LOG_DEGREE_XX
* @rotate: log file max rotate num
* @size: log file size
*/
func OpenLog(log_name string , filt_level int , log_degree int , rotate int , log_size int) *SLogPen

 

这里的参数就是日志文件名、过滤等级、日志粒度、日志滚动数以及单个日志文件的大小.

  • 记录日志 在获得SLogPen句柄之后,主要提供了以下的方法: 
  1. DEBUG 打印debug级别日志 func (lp *SLogPen) Debug(format string, arg ...interface{})

  2. INFO 打印info级别日志 func (lp *SLogPen) Info(format string, arg ...interface{})

  3. ERR 打印err级别日志  func (lp *SLogPen) Err(format string, arg ...interface{})

  4. FATAL 打印fatal级别日志 func (lp *SLogPen) Fatal(format string, arg ...interface{}

  • ATTR 动态修改句柄属性 func (lp *SLogPen) ChgAttr(attr int , value int) int

    • 过滤等级 LOG_ATTR_LEVEL
    • 日志粒度 LOG_ATTR_DEGREE
    • 日志滚动 LOG_ATTR_ROTATE
    • 日志大小 LOG_ATTR_SIZE
  • CLOSE 关闭句柄 func (lp *SLogPen) Close()

使用实例

我们以logic_serv为例来观看实际的代码使用.

  • 打开日志已经做成通用的了,放置于comm/config.go里:
...
//log
lp := log.OpenLog(log_file , log.LOG_DEFAULT_FILT_LEVEL , log.LOG_DEFAULT_DEGREE , log.LOG_DEFAULT_ROTATE , log.LOG_DEFAULT_SIZE);
if lp == nil {
    fmt.Printf("open log %s failed!\n" , log_file);
    return nil;
}
pconfig.Log = lp;
...

 

  • 实际的打印 代码位于logic_serv/lib/base.go
...
var log = pconfig.Comm.Log
log.Info("%s starts---%v", pconfig.ProcName, os.Args)
...

 

会在进程运行之目录下生成相应的日志和记录:

-rw-rw-r-- 1 nmsoccer nmsoccer 159836 Aug 14 15:16 logic_serv.log.0
...
[2020-08-14 15:15:49.545 info] logic_serv-1 starts---[./logic_serv -N sgame -p 20001 -P logic_serv-1 -f conf/logic_serv.json -D]
[2020-08-14 15:15:49.545 debug] <RecvHeartBeatReq> set  heartbeat server:30001 1597389337
[2020-08-14 15:15:49.545 debug] <RecvHeartBeatReq> set  heartbeat server:10001 1597389338
[2020-08-14 15:15:49.545 debug] <RecvHeartBeatReq> set  heartbeat server:40001 1597389340
[2020-08-14 15:15:49.545 debug] <RecvHeartBeatReq> set  heartbeat server:40002 1597389341
...

 

  • 进程退出时关闭 
...
//close log
if pconfig.Comm.Log != nil {
    pconfig.Comm.Log.Info("%s", "server exit...")
    pconfig.Comm.Log.Close()
}
...

 

网络日志

网络日志一般以结构化的文本方式进行发送,支持设置粒度和接收机器列表

API

  • 打开日志句柄
    支持设置目标机器地址列表peer_addr;发送到目标的方式method,日志粒度等. 返回句柄和解析错误的目标机器地址
  • method有以下几种方式
    • NETLOG_METHOD_SEQ = 1 直接选择第一个机器
    • NETLOG_METHOD_ALL = 2 发给所有的目标机器
    • NETLOG_METHOD_MOD = 3 对目标机器按hash_key取模;这里的hash_key就是打开句柄时填的参数,只有当method为这个选项时起效
    • NETLOG_METHOD_RAND = 4 随机选择一台目标机器(默认)

 

/*Open a NetLog handler
* @hash_key: if method is hash this is neccessary
* @peer_addr: recv net-log servers
* @method:refer NETLOG_METHOD_XX default:rand
* @log_degree: LOG_DEGREE_XX. default:second
* @return:*SNetLogPen , err_addr:which addr is invalid
 */
func OpenNetLog(hash_key int , peer_addr []string , method int , log_degree int) (*SNetLogPen, []string)
  • 发送日志,将会使用sep对后面的作为字符串数组的arg进行整合并发送到对端
    func (nlp *SNetLogPen) Log(sep string , arg ...string)
  • 关闭
    func (nlp *SNetLogPen) Close()

 使用实例

我们仍然以logic_serv为例来观看实际的代码使用

  • 打开网络日志句柄 示例代码位于logic_serv/lib/base.go
//NetLog
var bad_addr []string
pconfig.NetLog , bad_addr = llog.OpenNetLog(pconfig.ProcId , pconfig.FileConfig.NetLogAddr , pconfig.FileConfig.NetLogMethod , llog.NETLOG_DEFAULT_DEGREE)
if pconfig.NetLog == nil {
	log.Err("%s OpenNetLog:%v Failed!" , _func_ , pconfig.FileConfig.NetLogAddr)
	return false
}
if len(bad_addr) > 0 {
	log.Err("%s OpenNetLog:%v some addr fail! failed_addr:%v" , _func_ , pconfig.FileConfig.NetLogAddr , bad_addr)
	return false
}
log.Info("%s OpenNetLog:%v Method:%d Degree:%d success!" , _func_ , pconfig.FileConfig.NetLogAddr , pconfig.FileConfig.NetLogMethod , 
    llog.NETLOG_DEFAULT_DEGREE)

 

上面在配置里指定了对端机器NetLogAddr和方式,而粒度使用的是默认的秒级

cat sgame/servers/spush/tmpl/logic_serv.tmpl 
{
  "conn_serv":$conn_serv,
  "disp_serv_list":[40001,40002],
  "master_db":$master_db,
  "slave_db":$slave_db,
  "log_file":"logic_serv.log",
  "manage_addr":["$m_addr"],
  "net_log_addr":["127.0.0.1:8000" , "127.0.0.1:8001"],
  "net_log_method":2,
  "max_online":1500,
  "client_timeout":10,
  "monitor_inv":5
}

 

  • 记录日志 我们在玩家登陆,登出时分别打印其登入与登出流水.代码截于logic_serv/lib/login.go 
//登陆流水
log_content := fmt.Sprintf("%d|%s|LoginFlow|%d|%s|%s|%d" , pconfig.ProcId , pconfig.ProcName , uid , prsp.Name ,
prsp.UserInfo.BasicInfo.Addr,curr_ts)
pconfig.NetLog.Log("|" , log_content)

//登出流水
log_content := fmt.Sprintf("%d|%s|LogoutFlow|%d|%s|%d|%d" , pconfig.ProcId , pconfig.ProcName , uid , puser_info.BasicInfo.Name ,
    reason , curr_ts)
pconfig.NetLog.Log("|" , log_content)

 

然后使用nc工具监听于8000或8001端口,再使用客户端登陆sgame/client: ./game_cli -m 2 -p 18909 -c "login cs xxx" 

nc -lu 8000
2020-08-14 18:48:39|20001|logic_serv-1|LoginFlow|10002|cs|shenzhen|1597402119
2020-08-14 18:48:50|20001|logic_serv-1|LogoutFlow|10002|cs|4|1597402130

nc -lu 8001
2020-08-14 18:48:39|20001|logic_serv-1|LoginFlow|10002|cs|shenzhen|1597394919
2020-08-14 18:48:50|20001|logic_serv-1|LogoutFlow|10002|cs|4|1597402130

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值