mirror of
https://github.com/labring/sealos.git
synced 2026-09-24 15:46:19 +08:00
fix pkg
This commit is contained in:
Generated
+5
@@ -133,6 +133,11 @@
|
||||
"Comment": "v1.3.2",
|
||||
"Rev": "9e56dacc08fbbf8c9ee2dbc717553c758ce42bc9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/wonderivan/logger",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "11d39e135b9d8f7994e0b70b26df77bf207d75aa"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "c2843e01d9a2bc60bb26ad24e09734fdc2d9ec58"
|
||||
|
||||
+7
-8
@@ -15,7 +15,7 @@ kubernetes 1.14以下版本请移步老掉牙教程[sealos 1.x docs](https://git
|
||||
# 快速使用
|
||||
## 准备条件
|
||||
* 装好docker并启动docker
|
||||
* 把[离线安装包](http://store.lameleg.com) 下载好拷贝到所有节点的/root目录下, 不需要解压,如果有文件服务器更好,sealos支持从一个服务器上wget到所有节点上
|
||||
* 把[离线安装包](http://store.lameleg.com) 下载好拷贝到执行节点的任意目录,不需要解压,sealos会自动检测各个节点是否有安装包,若不存在则会scp到该节点。如果有文件服务器更好,sealos也支持从一个服务器上wget到所有节点上。
|
||||
|
||||
## 安装
|
||||
sealos已经放在离线包中,解压后在kube/bin目录下(可以解压一个,获取sealos bin文件)
|
||||
@@ -23,12 +23,12 @@ sealos已经放在离线包中,解压后在kube/bin目录下(可以解压一
|
||||
sealos init \
|
||||
--master 192.168.0.2 \
|
||||
--master 192.168.0.3 \
|
||||
--master 192.168.0.4 \ # master地址列表
|
||||
--node 192.168.0.5 \ # node地址列表
|
||||
--user root \ # 服务用户名
|
||||
--passwd your-server-password \ # 服务器密码,用于远程执行命令
|
||||
--pkg kube1.14.1.tar.gz \ # 离线安装包名称
|
||||
--version v1.14.1 # kubernetes 离线安装包版本,这渲染kubeadm配置时需要使用
|
||||
--master 192.168.0.4 \ # master地址列表
|
||||
--node 192.168.0.5 \ # node地址列表
|
||||
--user root \ # 服务用户名
|
||||
--passwd your-server-password \ # 服务器密码,用于远程执行命令
|
||||
--pkg-url /root/kube1.14.1.tar.gz \ # 离线安装包位置,可支持http/https服务器(http://store.lameleg.com/kube1.14.1.tar.gz)存放和本地(/root/kube1.14.1.tar.gz)存放两种方式。若对应节点上文件不存在则会从执行机器上scp文件到对应节点。
|
||||
--version v1.14.1 # kubernetes 离线安装包版本,这渲染kubeadm配置时需要使用
|
||||
```
|
||||
然后,就没有然后了
|
||||
|
||||
@@ -37,7 +37,6 @@ sealos init \
|
||||
|
||||
```
|
||||
--kubeadm-config string kubeadm-config.yaml local # 自定义kubeadm配置文件,如有这个sealos就不去渲染kubeadm配置
|
||||
--pkg-url string http://store.lameleg.com/kube1.14.1.tar.gz download offline pakage url # 支持从远程拉取离线包,省的每个机器拷贝,前提你得有个http服务器放离线包
|
||||
--vip string virtual ip (default "10.103.97.2") # 代理master的虚拟IP,只要与你地址不冲突请不要改
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -54,6 +54,6 @@ func init() {
|
||||
initCmd.Flags().StringSliceVar(&masters, "master", []string{}, "kubernetes masters")
|
||||
initCmd.Flags().StringSliceVar(&nodes, "node", []string{}, "kubernetes nodes")
|
||||
|
||||
initCmd.Flags().StringVar(&pkgURL, "pkg-url", "", "http://store.lameleg.com/kube1.14.1.tar.gz download offline pakage url")
|
||||
initCmd.Flags().StringVar(&pkgURL, "pkg-url", "", "http://store.lameleg.com/kube1.14.1.tar.gz download offline pakage url, or file localtion ex. /root/kube1.14.1.tar.gz")
|
||||
initCmd.Flags().StringVar(&install.Version, "version", "v1.14.1", "version is kubernetes version")
|
||||
}
|
||||
|
||||
+15
-11
@@ -23,7 +23,7 @@ func (s *SealosInstaller) SendPackage(url string) {
|
||||
wgetCommand = fmt.Sprintf(" wget %s ", wgetParam)
|
||||
}
|
||||
remoteCmd := fmt.Sprintf("cd /root && %s %s && tar zxvf %s", wgetCommand, url, pkg)
|
||||
localCmd := fmt.Sprintf("cd /root && tar zxvf %s ", pkg)
|
||||
localCmd := fmt.Sprintf("cd /root && rm -rf kube && tar zxvf %s ", pkg)
|
||||
kubeCmd := "cd /root/kube/shell && sh init.sh"
|
||||
kubeLocal := fmt.Sprintf("/root/%s", pkg)
|
||||
|
||||
@@ -34,14 +34,16 @@ func (s *SealosInstaller) SendPackage(url string) {
|
||||
go func(master string) {
|
||||
defer wm.Done()
|
||||
logger.Debug("please wait for tar zxvf exec")
|
||||
if isHttp {
|
||||
go WatchFileSize(master, kubeLocal, GetFileSize(url))
|
||||
Cmd(master, remoteCmd)
|
||||
if RemoteFilExist(master, kubeLocal) {
|
||||
logger.Warn("host is ", master, ", SendPackage: file is exist")
|
||||
} else {
|
||||
if !RemoteFilExist(master, kubeLocal) {
|
||||
if isHttp {
|
||||
go WatchFileSize(master, kubeLocal, GetFileSize(url))
|
||||
Cmd(master, remoteCmd)
|
||||
} else {
|
||||
Copy(master, url, kubeLocal)
|
||||
Cmd(master, localCmd)
|
||||
}
|
||||
Cmd(master, localCmd)
|
||||
}
|
||||
Cmd(master, kubeCmd)
|
||||
}(master)
|
||||
@@ -51,14 +53,16 @@ func (s *SealosInstaller) SendPackage(url string) {
|
||||
go func(node string) {
|
||||
defer wn.Done()
|
||||
logger.Debug("please wait for tar zxvf exec")
|
||||
if isHttp {
|
||||
go WatchFileSize(node, kubeLocal, GetFileSize(url))
|
||||
Cmd(node, remoteCmd)
|
||||
if RemoteFilExist(node, kubeLocal) {
|
||||
logger.Warn("host is ", node, ", SendPackage: file is exist")
|
||||
} else {
|
||||
if !RemoteFilExist(node, kubeLocal) {
|
||||
if isHttp {
|
||||
go WatchFileSize(node, kubeLocal, GetFileSize(url))
|
||||
Cmd(node, remoteCmd)
|
||||
} else {
|
||||
Copy(node, url, kubeLocal)
|
||||
Cmd(node, localCmd)
|
||||
}
|
||||
Cmd(node, localCmd)
|
||||
}
|
||||
Cmd(node, kubeCmd)
|
||||
}(node)
|
||||
|
||||
@@ -109,10 +109,6 @@ func RemoteFilExist(host, remoteFilePath string) bool {
|
||||
|
||||
//Copy is
|
||||
func Copy(host, localFilePath, remoteFilePath string) {
|
||||
if RemoteFilExist(host, remoteFilePath) {
|
||||
logger.Warn("host is ", host, ", scpCopy: file is exist")
|
||||
return
|
||||
}
|
||||
sftpClient, err := SftpConnect(User, Passwd, host)
|
||||
if err != nil {
|
||||
logger.Error("scpCopy:", err)
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# logger
|
||||
convenient log package
|
||||
|
||||
# 1. 使用说明
|
||||
```go
|
||||
import "github.com/wonderivan/logger"
|
||||
|
||||
// 配置logger,如果不配置时默认为控制台输出,等级为DEBG
|
||||
logger.SetLogger(`{"Console": {"level": "DEBG"}`)
|
||||
// 配置说明见下文
|
||||
|
||||
// 设置完成后,即可在控制台和日志文件app.log中看到如下输出
|
||||
logger.Trace("this is Trace")
|
||||
logger.Debug("this is Debug")
|
||||
logger.Info("this is Info")
|
||||
logger.Warn("this is Warn")
|
||||
logger.Error("this is Error")
|
||||
logger.Crit("this is Critical")
|
||||
logger.Alert("this is Alert")
|
||||
logger.Emer("this is Emergency")
|
||||
```
|
||||
输出结果:
|
||||
|
||||

|
||||
|
||||
# 2. 日志等级
|
||||
|
||||
当前日志输出等级共8种,从0-7对应的等级由高到底,当配置为某个输出等级时,只有大于等于该等级的日志才会输出。不同的输出适配器支持不同的日志等级配置:
|
||||
|
||||
| 等级 | 配置 | 释义 | 控制台颜色 |
|
||||
| ---- | ---- | ------------------------------------------------ | ---------- |
|
||||
| 0 | EMER | 系统级紧急,比如磁盘出错,内存异常,网络不可用等 | 红色底 |
|
||||
| 1 | ALRT | 系统级警告,比如数据库访问异常,配置文件出错等 | 紫色 |
|
||||
| 2 | CRIT | 系统级危险,比如权限出错,访问异常等 | 蓝色 |
|
||||
| 3 | EROR | 用户级错误 | 红色 |
|
||||
| 4 | WARN | 用户级警告 | 黄色 |
|
||||
| 5 | INFO | 用户级重要 | 天蓝色 |
|
||||
| 6 | DEBG | 用户级调试 | 绿色 |
|
||||
| 7 | TRAC | 用户级基本输出 | 绿色 |
|
||||
|
||||
|
||||
# 3. 配置说明
|
||||
logger当前支持控制台、文件、网络3种方式适配器输出,可以通过各自的参数进行设置,该logger支持多个方式同时输出,如果未配置某项适配器时,则不初始化也不会输出到该适配器。
|
||||
|
||||
通过调用logger.SetLogger(config string)方法设置参数,config支持json配置,也支持指定内容为json配置的文件路径,例如:
|
||||
```go
|
||||
// 通过配置参数直接配置
|
||||
logger.SetLogger(`{"Console": {"level": "DEBG"}}`)
|
||||
// 通过配置文件配置
|
||||
logger.SetLogger("/home/log.json")
|
||||
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"TimeFormat":"2006-01-02 15:04:05", // 输出日志开头时间格式
|
||||
"Console": { // 控制台日志配置
|
||||
"level": "TRAC", // 控制台日志输出等级
|
||||
"color": true // 控制台日志颜色开关
|
||||
},
|
||||
"File": { // 文件日志配置
|
||||
"filename": "app.log", // 初始日志文件名
|
||||
"level": "TRAC", // 日志文件日志输出等级
|
||||
"daily": true, // 跨天后是否创建新日志文件,当append=true时有效
|
||||
"maxlines": 1000000, // 日志文件最大行数,当append=true时有效
|
||||
"maxsize": 1, // 日志文件最大大小,当append=true时有效
|
||||
"maxdays": -1, // 日志文件有效期
|
||||
"append": true, // 是否支持日志追加
|
||||
"permit": "0660" // 新创建的日志文件权限属性
|
||||
},
|
||||
"Conn": { // 网络日志配置
|
||||
"net":"tcp", // 日志传输模式
|
||||
"addr":"10.1.55.10:1024", // 日志接收服务器
|
||||
"level": "Warn", // 网络日志输出等级
|
||||
"reconnect":true, // 网络断开后是否重连
|
||||
"reconnectOnMsg":false, // 发送完每条消息后是否断开网络
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 时间格式
|
||||
|
||||
| 时间类型 | 时间格式 |
|
||||
| ------------ | ----------------------------------------- |
|
||||
| ANSIC | "Mon Jan _2 15:04:05 2006" |
|
||||
| UnixDate | "Mon Jan _2 15:04:05 MST 2006" |
|
||||
| RubyDate | "Mon Jan 02 15:04:05 -0700 2006" |
|
||||
| RFC822 | "02 Jan 06 15:04 MST" |
|
||||
| RFC822Z | "02 Jan 06 15:04 -0700" |
|
||||
| RFC850 | "Monday, 02-Jan-06 15:04:05 MST" |
|
||||
| RFC1123 | "Mon, 02 Jan 2006 15:04:05 MST" |
|
||||
| RFC1123Z | "Mon, 02 Jan 2006 15:04:05 -0700" |
|
||||
| RFC3339 | "2006-01-02T15:04:05Z07:00" |
|
||||
| RFC3339Nano | "2006-01-02T15:04:05.999999999Z07:00" |
|
||||
| Kitchen | "3:04PM" |
|
||||
| Stamp | "Jan _2 15:04:05" |
|
||||
| StampMilli | "Jan _2 15:04:05.000" |
|
||||
| StampMicro | "Jan _2 15:04:05.000000" |
|
||||
| StampNano | "Jan _2 15:04:05.000000000" |
|
||||
| RFC3339Nano1 | "2006-01-02 15:04:05.999999999 -0700 MST" |
|
||||
| DEFAULT | "2006-01-02 15:04:05" |
|
||||
|
||||
- 时间格式打印:
|
||||
```
|
||||
========RFC1123Z time format========
|
||||
Thu, 02 Aug 2018 18:48:04 +0800 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC1123Z
|
||||
========Stamp time format========
|
||||
Aug 2 18:48:04 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug Stamp
|
||||
========StampMilli time format========
|
||||
Aug 2 18:48:04.489 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug StampMilli
|
||||
========StampNano time format========
|
||||
Aug 2 18:48:04.490002155 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug StampNano
|
||||
========RubyDate time format========
|
||||
Thu Aug 02 18:48:04 +0800 2018 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RubyDate
|
||||
========RFC822 time format========
|
||||
02 Aug 18 18:48 CST [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC822
|
||||
========RFC822Z time format========
|
||||
02 Aug 18 18:48 +0800 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC822Z
|
||||
========RFC1123 time format========
|
||||
Thu, 02 Aug 2018 18:48:04 CST [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC1123
|
||||
========RFC3339 time format========
|
||||
2018-08-02T18:48:04+08:00 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC3339
|
||||
========RFC3339Nano time format========
|
||||
2018-08-02T18:48:04.490377325+08:00 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC3339Nano
|
||||
========ANSIC time format========
|
||||
Thu Aug 2 18:48:04 2018 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug ANSIC
|
||||
========UnixDate time format========
|
||||
Thu Aug 2 18:48:04 CST 2018 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug UnixDate
|
||||
========RFC850 time format========
|
||||
Thursday, 02-Aug-18 18:48:04 CST [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug RFC850
|
||||
========Kitchen time format========
|
||||
6:48PM [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug Kitchen
|
||||
========StampMicro time format========
|
||||
Aug 2 18:48:04.490662 [DEBG] [github.com/wonderivan/logger/log_test.go:115] Debug StampMicro
|
||||
```
|
||||
|
||||
# 4. 其他
|
||||
|
||||
1. logger默认是控制台输出,输出等级为DEBG,默认是支持颜色区分的。
|
||||
2. 日志文件append为true时,当写入的日志文件发生跨天(daily为true)或超过最大限制时,会创建一个新文件,原有文件格式被重命名为: ****.xxxx-xx-xx.xxx.xxx 格式,例如:当向app.log写入日志时,触发了创建新文件操作,则将app.log重命名为 app.2018-01-01.001.log, 如果此时app.2018-01-01.001.log已经存在,则将刚才的app.log重命名为 app.2018-01-01.002.log,以此类推。
|
||||
3. logger package默认初始化了全局的defaultLogger,直接调用logger包的Debug方法时,会默认调用defaultLogger.Debug,所以普通调用时,仅需要import logger即可使用。
|
||||
4. 网络配置中的reconnectOnMsg为每条消息都重连一次网络日志中心,适用于写日志频率极低的情况下的服务调用,避免长时间连接,占用资源。但强烈不建议普通使用时设置为true,这将会导致调用方反复的网络重连,极大增加资源消耗和延迟。
|
||||
5. conn网络输出适配器经过ELK集成环境的测试验证,通过该方式发送的日志,能够正常通过Elecsearch和Kibana检索和分析
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type connLogger struct {
|
||||
sync.Mutex
|
||||
innerWriter io.WriteCloser
|
||||
ReconnectOnMsg bool `json:"reconnectOnMsg"`
|
||||
Reconnect bool `json:"reconnect"`
|
||||
Net string `json:"net"`
|
||||
Addr string `json:"addr"`
|
||||
Level string `json:"level"`
|
||||
LogLevel int
|
||||
illNetFlag bool //网络异常标记
|
||||
}
|
||||
|
||||
func (c *connLogger) Init(jsonConfig string) error {
|
||||
if len(jsonConfig) == 0 {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("consoleWriter Init:%s\n", jsonConfig)
|
||||
err := json.Unmarshal([]byte(jsonConfig), c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if l, ok := LevelMap[c.Level]; ok {
|
||||
c.LogLevel = l
|
||||
}
|
||||
if c.innerWriter != nil {
|
||||
c.innerWriter.Close()
|
||||
c.innerWriter = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *connLogger) LogWrite(when time.Time, msgText interface{}, level int) (err error) {
|
||||
if level > c.LogLevel {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg, ok := msgText.(*loginfo)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if c.needToConnectOnMsg() {
|
||||
err = c.connect()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//重连成功
|
||||
c.illNetFlag = false
|
||||
}
|
||||
|
||||
//每条消息都重连一次日志中心,适用于写日志频率极低的情况下的服务调用,避免长时间连接,占用资源
|
||||
if c.ReconnectOnMsg { // 频繁日志发送切勿开启
|
||||
defer c.innerWriter.Close()
|
||||
}
|
||||
|
||||
//网络异常时,消息发出
|
||||
if !c.illNetFlag {
|
||||
err = c.println(when, msg)
|
||||
//网络异常,通知处理网络的go程自动重连
|
||||
if err != nil {
|
||||
c.illNetFlag = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *connLogger) Destroy() {
|
||||
if c.innerWriter != nil {
|
||||
c.innerWriter.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connLogger) connect() error {
|
||||
if c.innerWriter != nil {
|
||||
c.innerWriter.Close()
|
||||
c.innerWriter = nil
|
||||
}
|
||||
addrs := strings.Split(c.Addr, ";")
|
||||
for _, addr := range addrs {
|
||||
conn, err := net.Dial(c.Net, addr)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "net.Dial error:%v\n", err)
|
||||
continue
|
||||
//return err
|
||||
}
|
||||
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetKeepAlive(true)
|
||||
}
|
||||
c.innerWriter = conn
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("hava no valid logs service addr:%v", c.Addr)
|
||||
}
|
||||
|
||||
func (c *connLogger) needToConnectOnMsg() bool {
|
||||
if c.Reconnect {
|
||||
c.Reconnect = false
|
||||
return true
|
||||
}
|
||||
|
||||
if c.innerWriter == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if c.illNetFlag {
|
||||
return true
|
||||
}
|
||||
return c.ReconnectOnMsg
|
||||
}
|
||||
|
||||
func (c *connLogger) println(when time.Time, msg *loginfo) error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
ss, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = c.innerWriter.Write(append(ss, '\n'))
|
||||
|
||||
//返回err,解决日志系统网络异常后的自动重连
|
||||
return err
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(AdapterConn, &connLogger{LogLevel: LevelTrace})
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type brush func(string) string
|
||||
|
||||
func newBrush(color string) brush {
|
||||
pre := "\033["
|
||||
reset := "\033[0m"
|
||||
return func(text string) string {
|
||||
return pre + color + "m" + text + reset
|
||||
}
|
||||
}
|
||||
|
||||
//鉴于终端的通常使用习惯,一般白色和黑色字体是不可行的,所以30,37不可用,
|
||||
var colors = []brush{
|
||||
newBrush("1;41"), // Emergency 红色底
|
||||
newBrush("1;35"), // Alert 紫色
|
||||
newBrush("1;34"), // Critical 蓝色
|
||||
newBrush("1;31"), // Error 红色
|
||||
newBrush("1;33"), // Warn 黄色
|
||||
newBrush("1;36"), // Informational 天蓝色
|
||||
newBrush("1;32"), // Debug 绿色
|
||||
newBrush("1;32"), // Trace 绿色
|
||||
}
|
||||
|
||||
type consoleLogger struct {
|
||||
sync.Mutex
|
||||
Level string `json:"level"`
|
||||
Colorful bool `json:"color"`
|
||||
LogLevel int
|
||||
}
|
||||
|
||||
func (c *consoleLogger) Init(jsonConfig string) error {
|
||||
if len(jsonConfig) == 0 {
|
||||
return nil
|
||||
}
|
||||
if jsonConfig != "{}" {
|
||||
fmt.Fprintf(os.Stdout, "consoleLogger Init:%s\n", jsonConfig)
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(jsonConfig), c)
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Colorful = false
|
||||
}
|
||||
|
||||
if l, ok := LevelMap[c.Level]; ok {
|
||||
c.LogLevel = l
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *consoleLogger) LogWrite(when time.Time, msgText interface{}, level int) error {
|
||||
if level > c.LogLevel {
|
||||
return nil
|
||||
}
|
||||
msg, ok := msgText.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if c.Colorful {
|
||||
msg = colors[level](msg)
|
||||
}
|
||||
c.printlnConsole(when, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *consoleLogger) Destroy() {
|
||||
|
||||
}
|
||||
|
||||
func (c *consoleLogger) printlnConsole(when time.Time, msg string) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
os.Stdout.Write(append([]byte(msg), '\n'))
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(AdapterConsole, &consoleLogger{
|
||||
LogLevel: LevelDebug,
|
||||
Colorful: runtime.GOOS != "windows",
|
||||
})
|
||||
}
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type fileLogger struct {
|
||||
sync.RWMutex
|
||||
fileWriter *os.File
|
||||
|
||||
Filename string `json:"filename"`
|
||||
Append bool `json:"append"`
|
||||
MaxLines int `json:"maxlines"`
|
||||
MaxSize int `json:"maxsize"`
|
||||
Daily bool `json:"daily"`
|
||||
MaxDays int64 `json:"maxdays"`
|
||||
Level string `json:"level"`
|
||||
PermitMask string `json:"permit"`
|
||||
|
||||
LogLevel int
|
||||
maxSizeCurSize int
|
||||
maxLinesCurLines int
|
||||
dailyOpenDate int
|
||||
dailyOpenTime time.Time
|
||||
fileNameOnly, suffix string
|
||||
}
|
||||
|
||||
// Init file logger with json config.
|
||||
// jsonConfig like:
|
||||
// {
|
||||
// "filename":"log/app.log",
|
||||
// "maxlines":10000,
|
||||
// "maxsize":1024,
|
||||
// "daily":true,
|
||||
// "maxdays":15,
|
||||
// "rotate":true,
|
||||
// "permit":"0600"
|
||||
// }
|
||||
func (f *fileLogger) Init(jsonConfig string) error {
|
||||
fmt.Printf("fileLogger Init:%s\n", jsonConfig)
|
||||
if len(jsonConfig) == 0 {
|
||||
return nil
|
||||
}
|
||||
err := json.Unmarshal([]byte(jsonConfig), f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(f.Filename) == 0 {
|
||||
return errors.New("jsonconfig must have filename")
|
||||
}
|
||||
f.suffix = filepath.Ext(f.Filename)
|
||||
f.fileNameOnly = strings.TrimSuffix(f.Filename, f.suffix)
|
||||
f.MaxSize *= 1024 * 1024 // 将单位转换成MB
|
||||
if f.suffix == "" {
|
||||
f.suffix = ".log"
|
||||
}
|
||||
if l, ok := LevelMap[f.Level]; ok {
|
||||
f.LogLevel = l
|
||||
}
|
||||
err = f.newFile()
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *fileLogger) needCreateFresh(size int, day int) bool {
|
||||
return (f.MaxLines > 0 && f.maxLinesCurLines >= f.MaxLines) ||
|
||||
(f.MaxSize > 0 && f.maxSizeCurSize+size >= f.MaxSize) ||
|
||||
(f.Daily && day != f.dailyOpenDate)
|
||||
|
||||
}
|
||||
|
||||
// WriteMsg write logger message into file.
|
||||
func (f *fileLogger) LogWrite(when time.Time, msgText interface{}, level int) error {
|
||||
msg, ok := msgText.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if level > f.LogLevel {
|
||||
return nil
|
||||
}
|
||||
|
||||
day := when.Day()
|
||||
msg += "\n"
|
||||
if f.Append {
|
||||
f.RLock()
|
||||
if f.needCreateFresh(len(msg), day) {
|
||||
f.RUnlock()
|
||||
f.Lock()
|
||||
if f.needCreateFresh(len(msg), day) {
|
||||
if err := f.createFreshFile(when); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "createFreshFile(%q): %s\n", f.Filename, err)
|
||||
}
|
||||
}
|
||||
f.Unlock()
|
||||
} else {
|
||||
f.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
f.Lock()
|
||||
_, err := f.fileWriter.Write([]byte(msg))
|
||||
if err == nil {
|
||||
f.maxLinesCurLines++
|
||||
f.maxSizeCurSize += len(msg)
|
||||
}
|
||||
f.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *fileLogger) createLogFile() (*os.File, error) {
|
||||
// Open the log file
|
||||
perm, err := strconv.ParseInt(f.PermitMask, 8, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fd, err := os.OpenFile(f.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
|
||||
if err == nil {
|
||||
// Make sure file perm is user set perm cause of `os.OpenFile` will obey umask
|
||||
os.Chmod(f.Filename, os.FileMode(perm))
|
||||
}
|
||||
return fd, err
|
||||
}
|
||||
|
||||
func (f *fileLogger) newFile() error {
|
||||
file, err := f.createLogFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.fileWriter != nil {
|
||||
f.fileWriter.Close()
|
||||
}
|
||||
f.fileWriter = file
|
||||
|
||||
fInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get stat err: %s", err)
|
||||
}
|
||||
f.maxSizeCurSize = int(fInfo.Size())
|
||||
f.dailyOpenTime = time.Now()
|
||||
f.dailyOpenDate = f.dailyOpenTime.Day()
|
||||
f.maxLinesCurLines = 0
|
||||
if f.maxSizeCurSize > 0 {
|
||||
count, err := f.lines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.maxLinesCurLines = count
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fileLogger) lines() (int, error) {
|
||||
fd, err := os.Open(f.Filename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
buf := make([]byte, 32768) // 32k
|
||||
count := 0
|
||||
lineSep := []byte{'\n'}
|
||||
|
||||
for {
|
||||
c, err := fd.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
return count, err
|
||||
}
|
||||
|
||||
count += bytes.Count(buf[:c], lineSep)
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// new file name like xx.2013-01-01.001.log
|
||||
func (f *fileLogger) createFreshFile(logTime time.Time) error {
|
||||
// file exists
|
||||
// Find the next available number
|
||||
num := 1
|
||||
fName := ""
|
||||
rotatePerm, err := strconv.ParseInt(f.PermitMask, 8, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = os.Lstat(f.Filename)
|
||||
if err != nil {
|
||||
// 初始日志文件不存在,无需创建新文件
|
||||
goto RESTART_LOGGER
|
||||
}
|
||||
// 日期变了, 说明跨天,重命名时需要保存为昨天的日期
|
||||
if f.dailyOpenDate != logTime.Day() {
|
||||
for ; err == nil && num <= 999; num++ {
|
||||
fName = f.fileNameOnly + fmt.Sprintf(".%s.%03d%s", f.dailyOpenTime.Format("2006-01-02"), num, f.suffix)
|
||||
_, err = os.Lstat(fName)
|
||||
}
|
||||
} else { //如果仅仅是文件大小或行数达到了限制,仅仅变更后缀序号即可
|
||||
for ; err == nil && num <= 999; num++ {
|
||||
fName = f.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, f.suffix)
|
||||
_, err = os.Lstat(fName)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Cannot find free log number to rename %s", f.Filename)
|
||||
}
|
||||
f.fileWriter.Close()
|
||||
|
||||
// 当创建新文件标记为true时
|
||||
// 当日志文件超过最大限制行
|
||||
// 当日志文件超过最大限制字节
|
||||
// 当日志文件隔天更新标记为true时
|
||||
// 将旧文件重命名,然后创建新文件
|
||||
err = os.Rename(f.Filename, fName)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "os.Rename %s to %s err:%s\n", f.Filename, fName, err.Error())
|
||||
goto RESTART_LOGGER
|
||||
}
|
||||
|
||||
err = os.Chmod(fName, os.FileMode(rotatePerm))
|
||||
|
||||
RESTART_LOGGER:
|
||||
|
||||
startLoggerErr := f.newFile()
|
||||
go f.deleteOldLog()
|
||||
|
||||
if startLoggerErr != nil {
|
||||
return fmt.Errorf("Rotate StartLogger: %s", startLoggerErr)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Rotate: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fileLogger) deleteOldLog() {
|
||||
dir := filepath.Dir(f.Filename)
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to delete old log '%s', error: %v\n", path, r)
|
||||
}
|
||||
}()
|
||||
|
||||
if info == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if f.MaxDays != -1 && !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(f.MaxDays)).Before(time.Now()) {
|
||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(f.fileNameOnly)) &&
|
||||
strings.HasSuffix(filepath.Base(path), f.suffix) {
|
||||
os.Remove(path)
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func (f *fileLogger) Destroy() {
|
||||
f.fileWriter.Close()
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(AdapterFile, &fileLogger{
|
||||
Daily: true,
|
||||
MaxDays: 7,
|
||||
Append: true,
|
||||
LogLevel: LevelDebug,
|
||||
PermitMask: "0777",
|
||||
MaxLines: 10,
|
||||
MaxSize: 10 * 1024 * 1024,
|
||||
})
|
||||
}
|
||||
+464
@@ -0,0 +1,464 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 默认日志输出
|
||||
var defaultLogger *LocalLogger
|
||||
|
||||
// 日志等级,从0-7,日优先级由高到低
|
||||
const (
|
||||
LevelEmergency = iota // 系统级紧急,比如磁盘出错,内存异常,网络不可用等
|
||||
LevelAlert // 系统级警告,比如数据库访问异常,配置文件出错等
|
||||
LevelCritical // 系统级危险,比如权限出错,访问异常等
|
||||
LevelError // 用户级错误
|
||||
LevelWarning // 用户级警告
|
||||
LevelInformational // 用户级信息
|
||||
LevelDebug // 用户级调试
|
||||
LevelTrace // 用户级基本输出
|
||||
)
|
||||
|
||||
// 日志等级和描述映射关系
|
||||
var LevelMap = map[string]int{
|
||||
"EMER": LevelEmergency,
|
||||
"ALRT": LevelAlert,
|
||||
"CRIT": LevelCritical,
|
||||
"EROR": LevelError,
|
||||
"WARN": LevelWarning,
|
||||
"INFO": LevelInformational,
|
||||
"DEBG": LevelDebug,
|
||||
"TRAC": LevelTrace,
|
||||
}
|
||||
|
||||
// 注册实现的适配器, 当前支持控制台,文件和网络输出
|
||||
var adapters = make(map[string]Logger)
|
||||
|
||||
// 日志记录等级字段
|
||||
var levelPrefix = [LevelTrace + 1]string{
|
||||
"EMER",
|
||||
"ALRT",
|
||||
"CRIT",
|
||||
"EROR",
|
||||
"WARN",
|
||||
"INFO",
|
||||
"DEBG",
|
||||
"TRAC",
|
||||
}
|
||||
|
||||
const (
|
||||
logTimeDefaultFormat = "2006-01-02 15:04:05" // 日志输出默认格式
|
||||
AdapterConsole = "console" // 控制台输出配置项
|
||||
AdapterFile = "file" // 文件输出配置项
|
||||
AdapterConn = "conn" // 网络输出配置项
|
||||
)
|
||||
|
||||
// log provider interface
|
||||
type Logger interface {
|
||||
Init(config string) error
|
||||
LogWrite(when time.Time, msg interface{}, level int) error
|
||||
Destroy()
|
||||
}
|
||||
|
||||
// 日志输出适配器注册,log需要实现Init,LogWrite,Destroy方法
|
||||
func Register(name string, log Logger) {
|
||||
if log == nil {
|
||||
panic("logs: Register provide is nil")
|
||||
}
|
||||
if _, ok := adapters[name]; ok {
|
||||
panic("logs: Register called twice for provider " + name)
|
||||
}
|
||||
adapters[name] = log
|
||||
}
|
||||
|
||||
type loginfo struct {
|
||||
Time string
|
||||
Level string
|
||||
Path string
|
||||
Name string
|
||||
Content string
|
||||
}
|
||||
|
||||
type nameLogger struct {
|
||||
Logger
|
||||
name string
|
||||
config string
|
||||
}
|
||||
|
||||
type LocalLogger struct {
|
||||
lock sync.Mutex
|
||||
init bool
|
||||
outputs []*nameLogger
|
||||
appName string
|
||||
callDepth int
|
||||
timeFormat string
|
||||
usePath string
|
||||
}
|
||||
|
||||
func NewLogger(depth ...int) *LocalLogger {
|
||||
dep := append(depth, 2)[0]
|
||||
l := new(LocalLogger)
|
||||
// appName用于记录网络传输时标记的程序发送方,
|
||||
// 通过环境变量APPSN进行设置,默认为NONE,此时无法通过网络日志检索区分不同服务发送方
|
||||
appSn := os.Getenv("APPSN")
|
||||
if appSn == "" {
|
||||
appSn = "NONE"
|
||||
}
|
||||
l.appName = "[" + appSn + "]"
|
||||
l.callDepth = dep
|
||||
l.SetLogger(AdapterConsole)
|
||||
l.timeFormat = logTimeDefaultFormat
|
||||
return l
|
||||
}
|
||||
|
||||
//配置文件
|
||||
type logConfig struct {
|
||||
TimeFormat string `json:"TimeFormat"`
|
||||
Console *consoleLogger `json:"Console,omitempty"`
|
||||
File *fileLogger `json:"File,omitempty"`
|
||||
Conn *connLogger `json:"Conn,omitempty"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
defaultLogger = NewLogger(3)
|
||||
}
|
||||
|
||||
func (this *LocalLogger) SetLogger(adapterName string, configs ...string) error {
|
||||
this.lock.Lock()
|
||||
defer this.lock.Unlock()
|
||||
|
||||
if !this.init {
|
||||
this.outputs = []*nameLogger{}
|
||||
this.init = true
|
||||
}
|
||||
|
||||
config := append(configs, "{}")[0]
|
||||
var num int = -1
|
||||
var i int
|
||||
var l *nameLogger
|
||||
for i, l = range this.outputs {
|
||||
if l.name == adapterName {
|
||||
if l.config == config {
|
||||
//配置没有变动,不重新设置
|
||||
return fmt.Errorf("you have set same config for this adaptername %s", adapterName)
|
||||
}
|
||||
l.Logger.Destroy()
|
||||
num = i
|
||||
break
|
||||
}
|
||||
}
|
||||
logger, ok := adapters[adapterName]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown adaptername %s (forgotten Register?)", adapterName)
|
||||
}
|
||||
|
||||
err := logger.Init(config)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "logger Init <%s> err:%v, %s output ignore!\n",
|
||||
adapterName, err, adapterName)
|
||||
return err
|
||||
}
|
||||
if num >= 0 {
|
||||
this.outputs[i] = &nameLogger{name: adapterName, Logger: logger, config: config}
|
||||
return nil
|
||||
}
|
||||
this.outputs = append(this.outputs, &nameLogger{name: adapterName, Logger: logger, config: config})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *LocalLogger) DelLogger(adapterName string) error {
|
||||
this.lock.Lock()
|
||||
defer this.lock.Unlock()
|
||||
outputs := []*nameLogger{}
|
||||
for _, lg := range this.outputs {
|
||||
if lg.name == adapterName {
|
||||
lg.Destroy()
|
||||
} else {
|
||||
outputs = append(outputs, lg)
|
||||
}
|
||||
}
|
||||
if len(outputs) == len(this.outputs) {
|
||||
return fmt.Errorf("logs: unknown adaptername %s (forgotten Register?)", adapterName)
|
||||
}
|
||||
this.outputs = outputs
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置日志起始路径
|
||||
func (this *LocalLogger) SetLogPathTrim(trimPath string) {
|
||||
this.usePath = trimPath
|
||||
}
|
||||
|
||||
func (this *LocalLogger) writeToLoggers(when time.Time, msg *loginfo, level int) {
|
||||
for _, l := range this.outputs {
|
||||
if l.name == AdapterConn {
|
||||
//网络日志,使用json格式发送,此处使用结构体,用于类似ElasticSearch功能检索
|
||||
err := l.LogWrite(when, msg, level)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
msgStr := when.Format(this.timeFormat) + " [" + msg.Level + "] " + "[" + msg.Path + "] " + msg.Content
|
||||
err := l.LogWrite(when, msgStr, level)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *LocalLogger) writeMsg(logLevel int, msg string, v ...interface{}) error {
|
||||
if !this.init {
|
||||
this.SetLogger(AdapterConsole)
|
||||
}
|
||||
msgSt := new(loginfo)
|
||||
src := ""
|
||||
if len(v) > 0 {
|
||||
msg = fmt.Sprintf(msg, v...)
|
||||
}
|
||||
when := time.Now()
|
||||
_, file, lineno, ok := runtime.Caller(this.callDepth)
|
||||
var strim string = "src/"
|
||||
if this.usePath != "" {
|
||||
strim = this.usePath
|
||||
}
|
||||
if ok {
|
||||
|
||||
src = strings.Replace(
|
||||
fmt.Sprintf("%s:%d", stringTrim(file, strim), lineno), "%2e", ".", -1)
|
||||
}
|
||||
|
||||
msgSt.Level = levelPrefix[logLevel]
|
||||
msgSt.Path = src
|
||||
msgSt.Content = msg
|
||||
msgSt.Name = this.appName
|
||||
msgSt.Time = when.Format(this.timeFormat)
|
||||
this.writeToLoggers(when, msgSt, logLevel)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *LocalLogger) Fatal(format string, args ...interface{}) {
|
||||
this.Emer("###Exec Panic:"+format, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (this *LocalLogger) Panic(format string, args ...interface{}) {
|
||||
this.Emer("###Exec Panic:"+format, args...)
|
||||
panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Emer Log EMERGENCY level message.
|
||||
func (this *LocalLogger) Emer(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelEmergency, format, v...)
|
||||
}
|
||||
|
||||
// Alert Log ALERT level message.
|
||||
func (this *LocalLogger) Alert(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelAlert, format, v...)
|
||||
}
|
||||
|
||||
// Crit Log CRITICAL level message.
|
||||
func (this *LocalLogger) Crit(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelCritical, format, v...)
|
||||
}
|
||||
|
||||
// Error Log ERROR level message.
|
||||
func (this *LocalLogger) Error(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelError, format, v...)
|
||||
}
|
||||
|
||||
// Warn Log WARNING level message.
|
||||
func (this *LocalLogger) Warn(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelWarning, format, v...)
|
||||
}
|
||||
|
||||
// Info Log INFO level message.
|
||||
func (this *LocalLogger) Info(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelInformational, format, v...)
|
||||
}
|
||||
|
||||
// Debug Log DEBUG level message.
|
||||
func (this *LocalLogger) Debug(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
// Trace Log TRAC level message.
|
||||
func (this *LocalLogger) Trace(format string, v ...interface{}) {
|
||||
this.writeMsg(LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
func (this *LocalLogger) Close() {
|
||||
|
||||
for _, l := range this.outputs {
|
||||
l.Destroy()
|
||||
}
|
||||
this.outputs = nil
|
||||
|
||||
}
|
||||
|
||||
func (this *LocalLogger) Reset() {
|
||||
for _, l := range this.outputs {
|
||||
l.Destroy()
|
||||
}
|
||||
this.outputs = nil
|
||||
}
|
||||
|
||||
func (this *LocalLogger) SetCallDepth(depth int) {
|
||||
this.callDepth = depth
|
||||
}
|
||||
|
||||
// GetlocalLogger returns the defaultLogger
|
||||
func GetlocalLogger() *LocalLogger {
|
||||
return defaultLogger
|
||||
}
|
||||
|
||||
// Reset will remove all the adapter
|
||||
func Reset() {
|
||||
defaultLogger.Reset()
|
||||
}
|
||||
|
||||
func SetLogPathTrim(trimPath string) {
|
||||
defaultLogger.SetLogPathTrim(trimPath)
|
||||
}
|
||||
|
||||
// param 可以是log配置文件名,也可以是log配置内容,默认DEBUG输出到控制台
|
||||
func SetLogger(param ...string) error {
|
||||
if 0 == len(param) {
|
||||
//默认只输出到控制台
|
||||
defaultLogger.SetLogger(AdapterConsole)
|
||||
return nil
|
||||
}
|
||||
|
||||
c := param[0]
|
||||
conf := new(logConfig)
|
||||
err := json.Unmarshal([]byte(c), conf)
|
||||
if err != nil { //不是json,就认为是配置文件,如果都不是,打印日志,然后退出
|
||||
// Open the configuration file
|
||||
fd, err := os.Open(c)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Could not open %s for configure: %s\n", c, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadAll(fd)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Could not read %s: %s\n", c, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(contents, conf)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Could not Unmarshal %s: %s\n", contents, err)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if conf.TimeFormat != "" {
|
||||
defaultLogger.timeFormat = conf.TimeFormat
|
||||
}
|
||||
if conf.Console != nil {
|
||||
console, _ := json.Marshal(conf.Console)
|
||||
defaultLogger.SetLogger(AdapterConsole, string(console))
|
||||
}
|
||||
if conf.File != nil {
|
||||
file, _ := json.Marshal(conf.File)
|
||||
defaultLogger.SetLogger(AdapterFile, string(file))
|
||||
}
|
||||
if conf.Conn != nil {
|
||||
conn, _ := json.Marshal(conf.Conn)
|
||||
defaultLogger.SetLogger(AdapterConn, string(conn))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Painc logs a message at emergency level and panic.
|
||||
func Painc(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Panic(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Fatal logs a message at emergency level and exit.
|
||||
func Fatal(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Fatal(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Emer logs a message at emergency level.
|
||||
func Emer(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Emer(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Alert logs a message at alert level.
|
||||
func Alert(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Alert(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Crit logs a message at critical level.
|
||||
func Crit(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Crit(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Error logs a message at error level.
|
||||
func Error(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Error(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Warn logs a message at warning level.
|
||||
func Warn(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Warn(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Info logs a message at info level.
|
||||
func Info(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Info(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Notice logs a message at debug level.
|
||||
func Debug(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Debug(formatLog(f, v...))
|
||||
}
|
||||
|
||||
// Trace logs a message at trace level.
|
||||
func Trace(f interface{}, v ...interface{}) {
|
||||
defaultLogger.Trace(formatLog(f, v...))
|
||||
}
|
||||
|
||||
func formatLog(f interface{}, v ...interface{}) string {
|
||||
var msg string
|
||||
switch f.(type) {
|
||||
case string:
|
||||
msg = f.(string)
|
||||
if len(v) == 0 {
|
||||
return msg
|
||||
}
|
||||
if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
|
||||
//format string
|
||||
} else {
|
||||
//do not contain format char
|
||||
msg += strings.Repeat(" %v", len(v))
|
||||
}
|
||||
default:
|
||||
msg = fmt.Sprint(f)
|
||||
if len(v) == 0 {
|
||||
return msg
|
||||
}
|
||||
msg += strings.Repeat(" %v", len(v))
|
||||
}
|
||||
return fmt.Sprintf(msg, v...)
|
||||
}
|
||||
|
||||
func stringTrim(s string, cut string) string {
|
||||
ss := strings.SplitN(s, cut, 2)
|
||||
if 1 == len(ss) {
|
||||
return ss[0]
|
||||
}
|
||||
return ss[1]
|
||||
}
|
||||
Reference in New Issue
Block a user