mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
Merge branch 'develop' into qiangg_gdb_struct_inherit
This commit is contained in:
@ -65,7 +65,6 @@ func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
|
||||
@ -4,17 +4,26 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gcrc32 provides useful API for CRC32 encryption/decryption algorithms.
|
||||
// Package gcrc32 provides useful API for CRC32 encryption algorithms.
|
||||
package gcrc32
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// Encrypt encrypts any type of variable using CRC32 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) uint32 {
|
||||
return crc32.ChecksumIEEE(gconv.Bytes(v))
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func EncryptString(v string) uint32 {
|
||||
return crc32.ChecksumIEEE([]byte(v))
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func EncryptBytes(v []byte) uint32 {
|
||||
return crc32.ChecksumIEEE(v)
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// @author: wenzi1<liyz23@qq.com>
|
||||
//
|
||||
// @author wenzi1<liyz23@qq.com>
|
||||
|
||||
// Package gdes provides useful API for DES encryption/decryption algorithms.
|
||||
package gdes
|
||||
@ -16,11 +17,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
NOPADDING = iota
|
||||
NOPADDING = iota
|
||||
PKCS5PADDING
|
||||
)
|
||||
|
||||
//ECB模式DES加密
|
||||
// ECB模式DES加密
|
||||
func DesECBEncrypt(key []byte, clearText []byte, padding int) ([]byte, error) {
|
||||
text, err := Padding(clearText, padding)
|
||||
if err != nil {
|
||||
@ -42,7 +43,7 @@ func DesECBEncrypt(key []byte, clearText []byte, padding int) ([]byte, error) {
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//ECB模式DES解密
|
||||
// ECB模式DES解密
|
||||
func DesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
text := make([]byte, len(cipherText))
|
||||
block, err := des.NewCipher(key)
|
||||
@ -63,7 +64,7 @@ func DesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//ECB模式3DES加密,密钥长度可以是16或24位长
|
||||
// ECB模式3DES加密,密钥长度可以是16或24位长
|
||||
func TripleDesECBEncrypt(key []byte, clearText []byte, padding int) ( []byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length error")
|
||||
@ -96,7 +97,7 @@ func TripleDesECBEncrypt(key []byte, clearText []byte, padding int) ( []byte, er
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//ECB模式3DES解密,密钥长度可以是16或24位长
|
||||
// ECB模式3DES解密,密钥长度可以是16或24位长
|
||||
func TripleDesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length error")
|
||||
@ -129,7 +130,7 @@ func TripleDesECBDecrypt(key []byte, cipherText []byte, padding int) ([]byte, e
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//CBC模式DES加密
|
||||
// CBC模式DES加密
|
||||
func DesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
@ -152,7 +153,7 @@ func DesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//CBC模式DES解密
|
||||
// CBC模式DES解密
|
||||
func DesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
@ -175,7 +176,7 @@ func DesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ([]byt
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//CBC模式3DES加密
|
||||
// CBC模式3DES加密
|
||||
func TripleDesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) ([]byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length invalid")
|
||||
@ -210,7 +211,7 @@ func TripleDesCBCEncrypt(key []byte, clearText []byte, iv []byte, padding int) (
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
//CBC模式3DES解密
|
||||
// CBC模式3DES解密
|
||||
func TripleDesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int) ( []byte, error) {
|
||||
if len(key) != 16 && len(key) != 24 {
|
||||
return nil, errors.New("key length invalid")
|
||||
@ -245,21 +246,21 @@ func TripleDesCBCDecrypt(key []byte, cipherText []byte, iv []byte, padding int)
|
||||
return clearText, nil
|
||||
}
|
||||
|
||||
//PKCS5补位
|
||||
// PKCS5补位
|
||||
func PKCS5Padding(text []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(text) % blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(text, padtext...)
|
||||
}
|
||||
|
||||
//去除PKCS5补位
|
||||
// 去除PKCS5补位
|
||||
func PKCS5Unpadding(text []byte) []byte{
|
||||
length := len(text)
|
||||
padtext := int(text[length - 1])
|
||||
return text[:(length - padtext)]
|
||||
}
|
||||
|
||||
//补位方法
|
||||
// 补位方法
|
||||
func Padding(text []byte, padding int)([]byte, error) {
|
||||
switch padding {
|
||||
case NOPADDING:
|
||||
@ -275,7 +276,7 @@ func Padding(text []byte, padding int)([]byte, error) {
|
||||
return text, nil
|
||||
}
|
||||
|
||||
//去除补位方法
|
||||
// 去除补位方法
|
||||
func UnPadding(text []byte, padding int)([]byte, error) {
|
||||
switch padding {
|
||||
case NOPADDING:
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gmd5 provides useful API for MD5 encryption/decryption algorithms.
|
||||
// Package gmd5 provides useful API for MD5 encryption algorithms.
|
||||
package gmd5
|
||||
|
||||
import (
|
||||
@ -15,28 +15,31 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 将任意类型的变量进行md5摘要(注意map等非排序变量造成的不同结果)
|
||||
// Encrypt encrypts any type of variable using MD5 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(gconv.Bytes(v)))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// 将字符串进行MD5哈希摘要计算
|
||||
|
||||
// Deprecated.
|
||||
func EncryptString(v string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(v))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
h := md5.New()
|
||||
h.Write([]byte(v))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
// 将文件内容进行MD5哈希摘要计算
|
||||
|
||||
// EncryptFile encrypts file content of <path> using MD5 algorithms.
|
||||
func EncryptFile(path string) string {
|
||||
f, e := os.Open(path)
|
||||
if e != nil {
|
||||
return ""
|
||||
}
|
||||
defer f.Close()
|
||||
h := md5.New()
|
||||
h := md5.New()
|
||||
_, e = io.Copy(h, f)
|
||||
if e != nil {
|
||||
return ""
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gsha1 provides useful API for SHA1 encryption/decryption algorithms.
|
||||
// Package gsha1 provides useful API for SHA1 encryption algorithms.
|
||||
package gsha1
|
||||
|
||||
import (
|
||||
@ -15,20 +15,20 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 将任意类型的变量进行SHA摘要(注意map等非排序变量造成的不同结果)
|
||||
// 内部使用了md5计算,因此效率会稍微差一些,更多情况请使用 EncodeString
|
||||
// Encrypt encrypts any type of variable using SHA1 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
func Encrypt(v interface{}) string {
|
||||
r := sha1.Sum(gconv.Bytes(v))
|
||||
return hex.EncodeToString(r[:])
|
||||
}
|
||||
|
||||
// 对字符串行SHA1摘要计算
|
||||
// Deprecated.
|
||||
func EncryptString(s string) string {
|
||||
r := sha1.Sum([]byte(s))
|
||||
return hex.EncodeToString(r[:])
|
||||
r := sha1.Sum([]byte(s))
|
||||
return hex.EncodeToString(r[:])
|
||||
}
|
||||
|
||||
// 对文件内容进行SHA1摘要计算
|
||||
// EncryptFile encrypts file content of <path> using SHA1 algorithms.
|
||||
func EncryptFile(path string) string {
|
||||
f, e := os.Open(path)
|
||||
if e != nil {
|
||||
|
||||
@ -64,29 +64,44 @@ func (j *Json) GetMap(pattern string, def...interface{}) map[string]interface{}
|
||||
}
|
||||
|
||||
// GetJson gets the value by specified <pattern>,
|
||||
// and converts it to a Json object.
|
||||
// and converts it to a un-concurrent-safe Json object.
|
||||
func (j *Json) GetJson(pattern string, def...interface{}) *Json {
|
||||
result := j.Get(pattern, def...)
|
||||
if result != nil {
|
||||
return New(result)
|
||||
return New(result, true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetJsons gets the value by specified <pattern>,
|
||||
// and converts it to a slice of Json object.
|
||||
// and converts it to a slice of un-concurrent-safe Json object.
|
||||
func (j *Json) GetJsons(pattern string, def...interface{}) []*Json {
|
||||
array := j.GetArray(pattern, def...)
|
||||
if len(array) > 0 {
|
||||
jsons := make([]*Json, len(array))
|
||||
jsonSlice := make([]*Json, len(array))
|
||||
for i := 0; i < len(array); i++ {
|
||||
jsons[i] = New(array[i], !j.mu.IsSafe())
|
||||
jsonSlice[i] = New(array[i], true)
|
||||
}
|
||||
return jsons
|
||||
return jsonSlice
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetJsonMap gets the value by specified <pattern>,
|
||||
// and converts it to a map of un-concurrent-safe Json object.
|
||||
func (j *Json) GetJsonMap(pattern string, def...interface{}) map[string]*Json {
|
||||
m := j.GetMap(pattern, def...)
|
||||
if len(m) > 0 {
|
||||
jsonMap := make(map[string]*Json, len(m))
|
||||
for k, v := range m {
|
||||
jsonMap[k] = New(v, true)
|
||||
}
|
||||
return jsonMap
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// GetArray gets the value by specified <pattern>,
|
||||
// and converts it to a slice of []interface{}.
|
||||
func (j *Json) GetArray(pattern string, def...interface{}) []interface{} {
|
||||
|
||||
@ -264,3 +264,39 @@ func TestJson_ToJson(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestJson_Default(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gjson.New(nil)
|
||||
gtest.AssertEQ(j.Get("no", 100), 100)
|
||||
gtest.AssertEQ(j.GetString("no", 100), "100")
|
||||
gtest.AssertEQ(j.GetBool("no", "on"), true)
|
||||
gtest.AssertEQ(j.GetInt("no", 100), 100)
|
||||
gtest.AssertEQ(j.GetInt8("no", 100), int8(100))
|
||||
gtest.AssertEQ(j.GetInt16("no", 100), int16(100))
|
||||
gtest.AssertEQ(j.GetInt32("no", 100), int32(100))
|
||||
gtest.AssertEQ(j.GetInt64("no", 100), int64(100))
|
||||
gtest.AssertEQ(j.GetUint("no", 100), uint(100))
|
||||
gtest.AssertEQ(j.GetUint8("no", 100), uint8(100))
|
||||
gtest.AssertEQ(j.GetUint16("no", 100), uint16(100))
|
||||
gtest.AssertEQ(j.GetUint32("no", 100), uint32(100))
|
||||
gtest.AssertEQ(j.GetUint64("no", 100), uint64(100))
|
||||
gtest.AssertEQ(j.GetFloat32("no", 123.456), float32(123.456))
|
||||
gtest.AssertEQ(j.GetFloat64("no", 123.456), float64(123.456))
|
||||
gtest.AssertEQ(j.GetArray("no", g.Slice{1,2,3}), g.Slice{1,2,3})
|
||||
gtest.AssertEQ(j.GetInts("no", g.Slice{1,2,3}), g.SliceInt{1,2,3})
|
||||
gtest.AssertEQ(j.GetFloats("no", g.Slice{1,2,3}), []float64{1,2,3})
|
||||
gtest.AssertEQ(j.GetMap("no", g.Map{"k":"v"}), g.Map{"k":"v"})
|
||||
gtest.AssertEQ(j.GetVar("no", 123.456).Float64(), float64(123.456))
|
||||
gtest.AssertEQ(j.GetJson("no", g.Map{"k":"v"}).Get("k"), "v")
|
||||
gtest.AssertEQ(j.GetJsons("no", g.Slice{
|
||||
g.Map{"k1":"v1"},
|
||||
g.Map{"k2":"v2"},
|
||||
g.Map{"k3":"v3"},
|
||||
})[0].Get("k1"), "v1")
|
||||
gtest.AssertEQ(j.GetJsonMap("no", g.Map{
|
||||
"m1" : g.Map{"k1":"v1"},
|
||||
"m2" : g.Map{"k2":"v2"},
|
||||
})["m2"].Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ type ServerConfig struct {
|
||||
// 日志配置
|
||||
LogPath string // 存放日志的目录路径(默认为空,表示不写文件)
|
||||
LogHandler LogHandler // 自定义日志处理回调方法(默认为空)
|
||||
LogStdPrint bool // 是否打印日志到终端(默认开启)
|
||||
LogStdout bool // 是否打印日志到终端(默认开启)
|
||||
ErrorLogEnabled bool // 是否开启error log(默认开启)
|
||||
AccessLogEnabled bool // 是否开启access log(默认关闭)
|
||||
|
||||
@ -111,7 +111,7 @@ var defaultServerConfig = ServerConfig {
|
||||
SessionMaxAge : gDEFAULT_SESSION_MAX_AGE,
|
||||
SessionIdName : gDEFAULT_SESSION_ID_NAME,
|
||||
|
||||
LogStdPrint : true,
|
||||
LogStdout : true,
|
||||
ErrorLogEnabled : true,
|
||||
AccessLogEnabled : false,
|
||||
GzipContentTypes : defaultGzipContentTypes,
|
||||
|
||||
@ -28,12 +28,12 @@ func (s *Server)SetLogPath(path string) {
|
||||
|
||||
// 设置日志内容是否输出到终端,默认情况下只有错误日志才会自动输出到终端。
|
||||
// 如果需要输出请求日志到终端,默认情况下使用SetAccessLogEnabled方法开启请求日志特性即可。
|
||||
func (s *Server)SetLogStdPrint(enabled bool) {
|
||||
func (s *Server)SetLogStdout(enabled bool) {
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
|
||||
return
|
||||
}
|
||||
s.config.LogStdPrint = enabled
|
||||
s.config.LogStdout = enabled
|
||||
}
|
||||
|
||||
// 设置是否开启access log日志功能
|
||||
|
||||
@ -32,7 +32,7 @@ func (s *Server) handleAccessLog(r *Request) {
|
||||
)
|
||||
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime - r.EnterTime)/1000)
|
||||
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
|
||||
s.logger.Cat("access").Backtrace(false, 2).StdPrint(s.config.LogStdPrint).Println(content)
|
||||
s.logger.Cat("access").Backtrace(false, 2).Stdout(s.config.LogStdout).Println(content)
|
||||
}
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
@ -60,5 +60,5 @@ func (s *Server) handleErrorLog(error interface{}, r *Request) {
|
||||
content += fmt.Sprintf(` %.3f`, float64(gtime.Microsecond() - r.EnterTime)/1000)
|
||||
}
|
||||
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
|
||||
s.logger.Cat("error").Backtrace(true, 2).StdPrint(s.config.LogStdPrint).Error(content)
|
||||
s.logger.Cat("error").Backtrace(true, 2).Stdout(s.config.LogStdout).Error(content)
|
||||
}
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gscanner provides a port scanner for local intranet.
|
||||
package gscanner
|
||||
|
||||
import (
|
||||
"net"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
"errors"
|
||||
"github.com/gogf/gf/g/net/gipv4"
|
||||
)
|
||||
|
||||
type scanner struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// 初始化一个扫描器
|
||||
func New() *scanner {
|
||||
return &scanner{
|
||||
6*time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// 设置超时时间,注意这个时间是每一次扫描的超时时间,而不是总共的超时时间
|
||||
func (s *scanner) SetTimeout(t time.Duration) *scanner {
|
||||
s.timeout = t
|
||||
return s
|
||||
}
|
||||
|
||||
// 异步TCP扫描网段及端口,如果扫描的端口是打开的,那么将链接给定给回调函数进行调用
|
||||
// 注意startIp和endIp需要是同一个网段,否则会报错,并且回调函数不会执行
|
||||
func (s *scanner) ScanIp(startIp string, endIp string, port int, callback func(net.Conn)) error {
|
||||
if callback == nil {
|
||||
return errors.New("callback function should not be nil")
|
||||
}
|
||||
var waitGroup sync.WaitGroup
|
||||
startIplong := gipv4.Ip2long(startIp)
|
||||
endIplong := gipv4.Ip2long(endIp)
|
||||
result := endIplong - startIplong
|
||||
if startIplong == 0 || endIplong == 0 {
|
||||
return errors.New("invalid startip or endip: ipv4 string should be given")
|
||||
}
|
||||
if result < 0 || result > 255 {
|
||||
return errors.New("invalid startip and endip: startip and endip should be in the same ip segment")
|
||||
}
|
||||
|
||||
for i := startIplong; i <= endIplong; i++ {
|
||||
waitGroup.Add(1)
|
||||
go func(ip string) {
|
||||
//fmt.Println("scanning:", ip)
|
||||
// 这里必需设置超时时间
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), s.timeout)
|
||||
if err == nil {
|
||||
callback(conn)
|
||||
conn.Close()
|
||||
}
|
||||
//fmt.Println("scanning:", ip, "done")
|
||||
waitGroup.Done()
|
||||
}(gipv4.Long2ip(i))
|
||||
}
|
||||
waitGroup.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 扫描目标主机打开的端口列表
|
||||
func (s *scanner) ScanPort(ip string, callback func(net.Conn)) error {
|
||||
if callback == nil {
|
||||
return errors.New("callback function should not be nil")
|
||||
}
|
||||
|
||||
var waitGroup sync.WaitGroup
|
||||
for i := 0; i <= 65536; i++ {
|
||||
waitGroup.Add(1)
|
||||
//fmt.Println("scanning:", i)
|
||||
go func(port int) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), s.timeout)
|
||||
if err == nil {
|
||||
callback(conn)
|
||||
conn.Close()
|
||||
}
|
||||
waitGroup.Done()
|
||||
}(i)
|
||||
}
|
||||
waitGroup.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gsmtp provides a SMTP client to access remote mail server.
|
||||
//
|
||||
// eg:
|
||||
// s := smtp.New("smtp.exmail.qq.com:25", "notify@a.com", "password")
|
||||
// glog.Println(s.SendMail("notify@a.com", "ulric@b.com;rain@c.com", "subject", "body, <font color=red>red</font>"))
|
||||
package gsmtp
|
||||
|
||||
import (
|
||||
@ -14,30 +18,31 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 示例:
|
||||
// s := smtp.New("smtp.exmail.qq.com:25", "notify@a.com", "password")
|
||||
// glog.Println(s.SendMail("notify@a.com", "ulric@b.com;rain@c.com", "这是subject", "这是body,<font color=red>red</font>"))
|
||||
|
||||
type Smtp struct {
|
||||
type SMTP struct {
|
||||
Address string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
func New(address, username, password string) *Smtp {
|
||||
return &Smtp{
|
||||
// New creates and returns a new SMTP object.
|
||||
func New(address, username, password string) *SMTP {
|
||||
return &SMTP{
|
||||
Address: address,
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Smtp) SendMail(from, tos, subject, body string, contentType ...string) error {
|
||||
if this.Address == "" {
|
||||
// SendMail connects to the server at addr, switches to TLS if
|
||||
// possible, authenticates with the optional mechanism a if possible,
|
||||
// and then sends an email from address from, to addresses to, with
|
||||
// message msg.
|
||||
func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) error {
|
||||
if s.Address == "" {
|
||||
return fmt.Errorf("address is necessary")
|
||||
}
|
||||
|
||||
hp := strings.Split(this.Address, ":")
|
||||
hp := strings.Split(s.Address, ":")
|
||||
if len(hp) != 2 {
|
||||
return fmt.Errorf("address format error")
|
||||
}
|
||||
@ -56,14 +61,13 @@ func (this *Smtp) SendMail(from, tos, subject, body string, contentType ...strin
|
||||
return fmt.Errorf("tos invalid")
|
||||
}
|
||||
|
||||
tos = strings.Join(safeArr, ";")
|
||||
|
||||
tos = strings.Join(safeArr, ";")
|
||||
b64 := base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
|
||||
|
||||
header := make(map[string]string)
|
||||
header["From"] = from
|
||||
header["To"] = tos
|
||||
header["Subject"] = fmt.Sprintf("=?UTF-8?B?%s?=", b64.EncodeToString([]byte(subject)))
|
||||
header := make(map[string]string)
|
||||
header["From"] = from
|
||||
header["To"] = tos
|
||||
header["Subject"] = fmt.Sprintf("=?UTF-8?B?%s?=", b64.EncodeToString([]byte(subject)))
|
||||
header["MIME-Version"] = "1.0"
|
||||
|
||||
ct := "text/plain; charset=UTF-8"
|
||||
@ -71,7 +75,7 @@ func (this *Smtp) SendMail(from, tos, subject, body string, contentType ...strin
|
||||
ct = "text/html; charset=UTF-8"
|
||||
}
|
||||
|
||||
header["Content-Type"] = ct
|
||||
header["Content-Type"] = ct
|
||||
header["Content-Transfer-Encoding"] = "base64"
|
||||
|
||||
message := ""
|
||||
@ -80,6 +84,6 @@ func (this *Smtp) SendMail(from, tos, subject, body string, contentType ...strin
|
||||
}
|
||||
message += "\r\n" + b64.EncodeToString([]byte(body))
|
||||
|
||||
auth := smtp.PlainAuth("", this.Username, this.Password, hp[0])
|
||||
return smtp.SendMail(this.Address, auth, from, strings.Split(tos, ";"), []byte(message))
|
||||
auth := smtp.PlainAuth("", s.Username, s.Password, hp[0])
|
||||
return smtp.SendMail(s.Address, auth, from, strings.Split(tos, ";"), []byte(message))
|
||||
}
|
||||
@ -27,23 +27,20 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// 文件分隔符
|
||||
// Separator for file system.
|
||||
Separator = string(filepath.Separator)
|
||||
// 默认的文件打开权限
|
||||
// Default perm for file opening.
|
||||
gDEFAULT_PERM = 0666
|
||||
)
|
||||
|
||||
var (
|
||||
// 源码的main包所在目录,仅仅会设置一次
|
||||
mainPkgPath = gtype.NewString()
|
||||
|
||||
// 编译时的 GOROOT 数值
|
||||
goRootOfBuild = gtype.NewString()
|
||||
// The absolute file path for main package.
|
||||
// It can be only checked and set once.
|
||||
mainPkgPath = gtype.NewString()
|
||||
)
|
||||
|
||||
// Create directories recursively.
|
||||
//
|
||||
// 给定目录的绝对路径创建目录(递归创建)。
|
||||
// Mkdir creates directories recursively with given <path>.
|
||||
// The parameter <path> is suggested to be absolute path.
|
||||
func Mkdir(path string) error {
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
@ -52,9 +49,8 @@ func Mkdir(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create file with given path recursively.
|
||||
//
|
||||
// 给定文件的绝对路径创建文件。
|
||||
// Create creates file with given <path> recursively.
|
||||
// The parameter <path> is suggested to be absolute path.
|
||||
func Create(path string) (*os.File, error) {
|
||||
dir := Dir(path)
|
||||
if !Exists(dir) {
|
||||
@ -63,23 +59,17 @@ func Create(path string) (*os.File, error) {
|
||||
return os.Create(path)
|
||||
}
|
||||
|
||||
// Open file/directory with readonly.
|
||||
//
|
||||
// 只读打开文件
|
||||
// Open opens file/directory readonly.
|
||||
func Open(path string) (*os.File, error) {
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
// Open file/directory with given <flag> and <perm>.
|
||||
//
|
||||
// 打开文件(带flag&perm)
|
||||
// OpenFile opens file/directory with given <flag> and <perm>.
|
||||
func OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
return os.OpenFile(path, flag, perm)
|
||||
}
|
||||
|
||||
// Open file/directory with default perm and given <flag>.
|
||||
//
|
||||
// 打开文件(带flag)
|
||||
// OpenWithFlag opens file/directory with default perm and given <flag>.
|
||||
func OpenWithFlag(path string, flag int) (*os.File, error) {
|
||||
f, err := os.OpenFile(path, flag, gDEFAULT_PERM)
|
||||
if err != nil {
|
||||
@ -88,9 +78,7 @@ func OpenWithFlag(path string, flag int) (*os.File, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Open file/directory with given <flag> and <perm>.
|
||||
//
|
||||
// 打开文件(带flag&perm)
|
||||
// OpenWithFlagPerm opens file/directory with given <flag> and <perm>.
|
||||
func OpenWithFlagPerm(path string, flag int, perm int) (*os.File, error) {
|
||||
f, err := os.OpenFile(path, flag, os.FileMode(perm))
|
||||
if err != nil {
|
||||
@ -99,9 +87,7 @@ func OpenWithFlagPerm(path string, flag int, perm int) (*os.File, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Check whether given path exist.
|
||||
//
|
||||
// 判断所给路径文件/文件夹是否存在
|
||||
// Exists checks whether given <path> exist.
|
||||
func Exists(path string) bool {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
return true
|
||||
@ -109,9 +95,7 @@ func Exists(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check whether given path a directory.
|
||||
//
|
||||
// 判断所给路径是否为文件夹
|
||||
// IsDir checks whether given <path> a directory.
|
||||
func IsDir(path string) bool {
|
||||
s, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@ -120,17 +104,13 @@ func IsDir(path string) bool {
|
||||
return s.IsDir()
|
||||
}
|
||||
|
||||
// Get current working directory absolute path.
|
||||
//
|
||||
// 获取当前工作目录(注意与SelfDir的区别).
|
||||
// Pwd returns absolute path of current working directory.
|
||||
func Pwd() string {
|
||||
path, _ := os.Getwd()
|
||||
return path
|
||||
}
|
||||
|
||||
// Check whether given path a file(not a directory).
|
||||
//
|
||||
// 判断所给路径是否为文件
|
||||
// IsFile checks whether given <path> a file, which means it's not a directory.
|
||||
func IsFile(path string) bool {
|
||||
s, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@ -139,39 +119,32 @@ func IsFile(path string) bool {
|
||||
return !s.IsDir()
|
||||
}
|
||||
|
||||
// Alias of Stat.
|
||||
// See Stat.
|
||||
//
|
||||
// Stat 方法的别名。
|
||||
func Info(path string) (os.FileInfo, error) {
|
||||
return Stat(path)
|
||||
}
|
||||
|
||||
// Stat returns a FileInfo describing the named file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
//
|
||||
// 获取文件或目录信息.
|
||||
func Stat(path string) (os.FileInfo, error) {
|
||||
return os.Stat(path)
|
||||
}
|
||||
|
||||
// Move renames (moves) src to dst path.
|
||||
//
|
||||
// 文件移动/重命名
|
||||
// Move renames (moves) <src> to <dst> path.
|
||||
func Move(src string, dst string) error {
|
||||
return os.Rename(src, dst)
|
||||
}
|
||||
|
||||
// Rename renames (moves) src to dst path.
|
||||
//
|
||||
// 文件移动/重命名.
|
||||
// Alias of Move.
|
||||
// See Move.
|
||||
func Rename(src string, dst string) error {
|
||||
return Move(src, dst)
|
||||
}
|
||||
|
||||
// Copy file from src to dst.
|
||||
// Copy file from <src> to <dst>.
|
||||
//
|
||||
// 文件复制.
|
||||
// @TODO 支持目录复制.
|
||||
// @TODO directory copy support.
|
||||
func Copy(src string, dst string) error {
|
||||
srcFile, err := Open(src)
|
||||
if err != nil {
|
||||
@ -194,9 +167,7 @@ func Copy(src string, dst string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get sub-file names of path.
|
||||
//
|
||||
// 返回目录下的文件名列表
|
||||
// DirNames returns sub-file names of given directory <path>.
|
||||
func DirNames(path string) ([]string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
@ -218,8 +189,6 @@ func DirNames(path string) ([]string, error) {
|
||||
// Glob ignores file system errors such as I/O errors reading directories.
|
||||
// The only possible returned error is ErrBadPattern, when pattern
|
||||
// is malformed.
|
||||
//
|
||||
// 文件名正则匹配查找,第二个可选参数指定返回的列表是否仅为文件名(非绝对路径),默认返回绝对路径
|
||||
func Glob(pattern string, onlyNames...bool) ([]string, error) {
|
||||
if list, err := filepath.Glob(pattern); err == nil {
|
||||
if len(onlyNames) > 0 && onlyNames[0] && len(list) > 0 {
|
||||
@ -235,16 +204,13 @@ func Glob(pattern string, onlyNames...bool) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove file/directory with <path> parameter.
|
||||
//
|
||||
// 文件/目录删除
|
||||
// Remove deletes all file/directory with <path> parameter.
|
||||
// If parameter <path> is directory, it deletes it recursively.
|
||||
func Remove(path string) error {
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
|
||||
// Check whether given <path> is readable.
|
||||
//
|
||||
// 文件是否可读(支持文件/目录)
|
||||
// IsReadable checks whether given <path> is readable.
|
||||
func IsReadable(path string) bool {
|
||||
result := true
|
||||
file, err := os.OpenFile(path, os.O_RDONLY, gDEFAULT_PERM)
|
||||
@ -255,14 +221,13 @@ func IsReadable(path string) bool {
|
||||
return result
|
||||
}
|
||||
|
||||
// Check whether given <path> is writable.
|
||||
// IsWritable checks whether given <path> is writable.
|
||||
//
|
||||
// 文件是否可写(支持文件/目录)
|
||||
// @TODO 改进性能,利用 golang.org/x/sys 来实现跨平台的权限判断。
|
||||
// @TODO improve performance; use golang.org/x/sys to cross-plat-form
|
||||
func IsWritable(path string) bool {
|
||||
result := true
|
||||
if IsDir(path) {
|
||||
// 如果是目录,那么创建一个临时文件进行写入测试
|
||||
// If it's a directory, create a temporary file to test whether it's writable.
|
||||
tmpFile := strings.TrimRight(path, Separator) + Separator + gconv.String(time.Now().UnixNano())
|
||||
if f, err := Create(tmpFile); err != nil || !Exists(tmpFile){
|
||||
result = false
|
||||
@ -282,16 +247,12 @@ func IsWritable(path string) bool {
|
||||
}
|
||||
|
||||
// See os.Chmod.
|
||||
//
|
||||
// 修改文件/目录权限
|
||||
func Chmod(path string, mode os.FileMode) error {
|
||||
return os.Chmod(path, mode)
|
||||
}
|
||||
|
||||
// Get all sub-files(absolute) of given <path>,
|
||||
// can be recursively with given parameter <recursive> true.
|
||||
//
|
||||
// 打开目录,并返回其下一级文件列表(绝对路径),按照文件名称大小写进行排序,支持目录递归遍历。
|
||||
// ScanDir returns all sub-files with absolute paths of given <path>,
|
||||
// It scans directory recursively if given parameter <recursive> is true.
|
||||
func ScanDir(path string, pattern string, recursive ... bool) ([]string, error) {
|
||||
list, err := doScanDir(path, pattern, recursive...)
|
||||
if err != nil {
|
||||
@ -303,22 +264,24 @@ func ScanDir(path string, pattern string, recursive ... bool) ([]string, error)
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// 内部检索目录方法,支持递归,返回没有排序的文件绝对路径列表结果。
|
||||
// pattern参数支持多个文件名称模式匹配,使用','符号分隔多个模式。
|
||||
// doScanDir is an internal method which scans directory
|
||||
// and returns the absolute path list of files that are not sorted.
|
||||
//
|
||||
// The pattern parameter <pattern> supports multiple file name patterns,
|
||||
// using the ',' symbol to separate multiple patterns.
|
||||
//
|
||||
// It scans directory recursively if given parameter <recursive> is true.
|
||||
func doScanDir(path string, pattern string, recursive ... bool) ([]string, error) {
|
||||
list := ([]string)(nil)
|
||||
// 打开目录
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
// 读取目录下的文件列表
|
||||
names, err := file.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 是否递归遍历
|
||||
for _, name := range names {
|
||||
path := fmt.Sprintf("%s%s%s", path, Separator, name)
|
||||
if IsDir(path) && len(recursive) > 0 && recursive[0] {
|
||||
@ -327,7 +290,7 @@ func doScanDir(path string, pattern string, recursive ... bool) ([]string, error
|
||||
list = append(list, array...)
|
||||
}
|
||||
}
|
||||
// 满足pattern才加入结果列表
|
||||
// If it meets pattern, then add it to the result list.
|
||||
for _, p := range strings.Split(pattern, ",") {
|
||||
if match, err := filepath.Match(strings.TrimSpace(p), name); err == nil && match {
|
||||
list = append(list, path)
|
||||
@ -337,10 +300,9 @@ func doScanDir(path string, pattern string, recursive ... bool) ([]string, error
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// See filepath.Abs.
|
||||
//
|
||||
// 将所给定的路径转换为绝对路径
|
||||
// 并判断文件路径是否存在,如果文件不存在,那么返回空字符串
|
||||
// RealPath converts the given <path> to its absolute path
|
||||
// and checks if the file path exists.
|
||||
// If the file does not exist, return an empty string.
|
||||
func RealPath(path string) string {
|
||||
p, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
@ -352,45 +314,46 @@ func RealPath(path string) string {
|
||||
return p
|
||||
}
|
||||
|
||||
// Get absolute file path of current running process(binary).
|
||||
//
|
||||
// 获取当前执行文件的绝对路径
|
||||
// SelfPath returns absolute file path of current running process(binary).
|
||||
func SelfPath() string {
|
||||
p, _ := filepath.Abs(os.Args[0])
|
||||
return p
|
||||
}
|
||||
|
||||
// Get absolute directory path of current running process(binary).
|
||||
//
|
||||
// 获取当前执行文件的目录绝对路径
|
||||
// SelfDir returns absolute directory path of current running process(binary).
|
||||
func SelfDir() string {
|
||||
return filepath.Dir(SelfPath())
|
||||
}
|
||||
|
||||
// See filepath.Base.
|
||||
//
|
||||
// 获取指定文件路径的文件名称
|
||||
// Basename returns the last element of path.
|
||||
// Trailing path separators are removed before extracting the last element.
|
||||
// If the path is empty, Base returns ".".
|
||||
// If the path consists entirely of separators, Base returns a single separator.
|
||||
func Basename(path string) string {
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
// See filepath.Dir.
|
||||
//
|
||||
// 获取指定文件路径的目录地址绝对路径.
|
||||
// Dir returns all but the last element of path, typically the path's directory.
|
||||
// After dropping the final element, Dir calls Clean on the path and trailing
|
||||
// slashes are removed.
|
||||
// If the path is empty, Dir returns ".".
|
||||
// If the path consists entirely of separators, Dir returns a single separator.
|
||||
// The returned path does not end in a separator unless it is the root directory.
|
||||
func Dir(path string) string {
|
||||
return filepath.Dir(path)
|
||||
}
|
||||
|
||||
// See filepath.Ext.
|
||||
// Ext returns the file name extension used by path.
|
||||
// The extension is the suffix beginning at the final dot
|
||||
// in the final element of path; it is empty if there is
|
||||
// no dot.
|
||||
//
|
||||
// 获取指定文件路径的文件扩展名(包含"."号)
|
||||
// Note: the result contains symbol '.'.
|
||||
func Ext(path string) string {
|
||||
return filepath.Ext(path)
|
||||
}
|
||||
|
||||
// Get absolute home directory path of current user.
|
||||
//
|
||||
// 获取用户主目录
|
||||
// Home returns absolute path of current user's home directory.
|
||||
func Home() (string, error) {
|
||||
u, err := user.Current()
|
||||
if nil == err {
|
||||
@ -435,12 +398,15 @@ func homeWindows() (string, error) {
|
||||
return home, nil
|
||||
}
|
||||
|
||||
// Get absolute file path of main file, which contains the entrance function main.
|
||||
// Available in develop environment.
|
||||
// MainPkgPath returns absolute file path of package main,
|
||||
// which contains the entrance function main.
|
||||
//
|
||||
// 获取入口函数文件所在目录(main包文件目录),
|
||||
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**。
|
||||
// 注意:该方法被第一次调用时,如果是在异步的goroutine中,该方法可能无法获取到main包路径。
|
||||
// It's only available in develop environment.
|
||||
//
|
||||
// Note1: Only valid for source development environments,
|
||||
// IE only valid for systems that generate this executable.
|
||||
// Note2: When the method is called for the first time, if it is in an asynchronous goroutine,
|
||||
// the method may not get the main package path.
|
||||
func MainPkgPath() string {
|
||||
path := mainPkgPath.Val()
|
||||
if path != "" {
|
||||
@ -473,14 +439,13 @@ func MainPkgPath() string {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 找不到,下次不用再检索了
|
||||
// If it fails finding the path, then mark it as "-",
|
||||
// which means it will never do this search again.
|
||||
mainPkgPath.Set("-")
|
||||
return ""
|
||||
}
|
||||
|
||||
// See os.TempDir().
|
||||
//
|
||||
// 系统临时目录
|
||||
func TempDir() string {
|
||||
return os.TempDir()
|
||||
}
|
||||
|
||||
@ -13,18 +13,18 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// 方法中涉及到读取的时候的缓冲大小
|
||||
gREAD_BUFFER = 1024
|
||||
// 方法中涉及到文件指针池的默认缓存时间(毫秒)
|
||||
//gFILE_POOL_EXPIRE = 60000
|
||||
// Buffer size for reading file content.
|
||||
gREAD_BUFFER = 1024
|
||||
)
|
||||
|
||||
// (文本)读取文件内容
|
||||
// GetContents returns the file content of <path> as string.
|
||||
// It returns en empty string if it fails reading.
|
||||
func GetContents(path string) string {
|
||||
return string(GetBinContents(path))
|
||||
}
|
||||
|
||||
// (二进制)读取文件内容,如果文件不存在或者读取失败,返回nil。
|
||||
// GetBinContents returns the file content of <path> as []byte.
|
||||
// It returns nil if it fails reading.
|
||||
func GetBinContents(path string) []byte {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
@ -33,16 +33,16 @@ func GetBinContents(path string) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
// 写入文件内容
|
||||
// putContents puts binary content to file of <path>.
|
||||
func putContents(path string, data []byte, flag int, perm int) error {
|
||||
// 支持目录递归创建
|
||||
// It supports creating file of <path> recursively.
|
||||
dir := Dir(path)
|
||||
if !Exists(dir) {
|
||||
if err := Mkdir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 创建/打开文件
|
||||
// Opening file with given <flag> and <perm>.
|
||||
f, err := OpenWithFlagPerm(path, flag, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -56,32 +56,36 @@ func putContents(path string, data []byte, flag int, perm int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Truncate
|
||||
// Truncate truncates file of <path> to given size by <size>.
|
||||
func Truncate(path string, size int) error {
|
||||
return os.Truncate(path, int64(size))
|
||||
}
|
||||
|
||||
// (文本)写入文件内容
|
||||
// PutContents puts string <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutContents(path string, content string) error {
|
||||
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// (文本)追加内容到文件末尾
|
||||
// PutContentsAppend appends string <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutContentsAppend(path string, content string) error {
|
||||
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// (二进制)写入文件内容
|
||||
// PutBinContents puts binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutBinContents(path string, content []byte) error {
|
||||
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// (二进制)追加内容到文件末尾
|
||||
// PutBinContentsAppend appends binary <content> to file of <path>.
|
||||
// It creates file of <path> recursively if it does not exist.
|
||||
func PutBinContentsAppend(path string, content []byte) error {
|
||||
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, gDEFAULT_PERM)
|
||||
}
|
||||
|
||||
// 获得文件内容下一个指定字节的位置
|
||||
// GetNextCharOffset returns the file offset for given <char> starting from <start>.
|
||||
func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {
|
||||
buffer := make([]byte, gREAD_BUFFER)
|
||||
offset := start
|
||||
@ -100,7 +104,8 @@ func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 获得文件内容下一个指定字节的位置
|
||||
// GetNextCharOffsetByPath returns the file offset for given <char> starting from <start>.
|
||||
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
|
||||
func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
defer f.Close()
|
||||
@ -109,7 +114,10 @@ func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 获得文件内容直到下一个指定字节的位置(返回值包含该位置字符内容)
|
||||
// GetBinContentsTilChar returns the contents of the file as []byte
|
||||
// until the next specified byte <char> position.
|
||||
//
|
||||
// Note: Returned value contains the character of the last position.
|
||||
func GetBinContentsTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
|
||||
if offset := GetNextCharOffset(reader, char, start); offset != -1 {
|
||||
return GetBinContentsByTwoOffsets(reader, start, offset + 1), offset
|
||||
@ -117,7 +125,11 @@ func GetBinContentsTilChar(reader io.ReaderAt, char byte, start int64) ([]byte,
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// 获得文件内容直到下一个指定字节的位置(返回值包含该位置字符内容)
|
||||
// GetBinContentsTilCharByPath returns the contents of the file given by <path> as []byte
|
||||
// until the next specified byte <char> position.
|
||||
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
|
||||
//
|
||||
// Note: Returned value contains the character of the last position.
|
||||
func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
defer f.Close()
|
||||
@ -126,7 +138,9 @@ func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, i
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// 获得文件内容中两个offset之间的内容 [start, end)
|
||||
// GetBinContentsByTwoOffsets returns the binary content as []byte from <start> to <end>.
|
||||
// Note: Returned value does not contain the character of the last position, which means
|
||||
// it returns content range as [start, end).
|
||||
func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
|
||||
buffer := make([]byte, end - start)
|
||||
if _, err := reader.ReadAt(buffer, start); err != nil {
|
||||
@ -135,7 +149,10 @@ func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []by
|
||||
return buffer
|
||||
}
|
||||
|
||||
// 获得文件内容中两个offset之间的内容 [start, end)
|
||||
// GetBinContentsByTwoOffsetsByPath returns the binary content as []byte from <start> to <end>.
|
||||
// Note: Returned value does not contain the character of the last position, which means
|
||||
// it returns content range as [start, end).
|
||||
// It opens file of <path> for reading with os.O_RDONLY flag and default perm.
|
||||
func GetBinContentsByTwoOffsetsByPath(path string, start int64, end int64) []byte {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
defer f.Close()
|
||||
|
||||
@ -13,31 +13,25 @@ import (
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
)
|
||||
|
||||
|
||||
// 如果给定绝对路径将会去掉其中的相对路径符号后返回;
|
||||
// 如果是给定的相对路径,那么将会按照以下路径优先级搜索文件(重复路径会去重):
|
||||
// prioritySearchPaths、当前工作目录、二进制文件目录、源码main包目录(开发环境下)
|
||||
// Search searches file by name <name> in following paths with priority:
|
||||
// prioritySearchPaths, Pwd()、SelfDir()、MainPkgPath().
|
||||
// It returns the absolute file path of <name> if found, or en empty string if not found.
|
||||
func Search(name string, prioritySearchPaths...string) (realPath string, err error) {
|
||||
// 是否绝对路径
|
||||
// Check if it's a absolute path.
|
||||
realPath = RealPath(name)
|
||||
if realPath != "" {
|
||||
return
|
||||
}
|
||||
// 相对路径搜索
|
||||
// Search paths array.
|
||||
array := garray.NewStringArray(true)
|
||||
// 自定义优先路径
|
||||
array.Append(prioritySearchPaths...)
|
||||
// 用户工作目录
|
||||
array.Append(Pwd())
|
||||
// 二进制所在目录
|
||||
array.Append(SelfDir())
|
||||
// 源码main包目录
|
||||
array.Append(Pwd(), SelfDir())
|
||||
if path := MainPkgPath(); path != "" {
|
||||
array.Append(path)
|
||||
}
|
||||
// 路径去重
|
||||
// Remove repeated items.
|
||||
array.Unique()
|
||||
// 执行相对路径搜索
|
||||
// Do the searching.
|
||||
array.RLockFunc(func(array []string) {
|
||||
path := ""
|
||||
for _, v := range array {
|
||||
@ -48,7 +42,7 @@ func Search(name string, prioritySearchPaths...string) (realPath string, err err
|
||||
}
|
||||
}
|
||||
})
|
||||
// 目录不存在错误处理
|
||||
// If it fails searching, it returns formatted error.
|
||||
if realPath == "" {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString(fmt.Sprintf("cannot find file/folder \"%s\" in following paths:", name))
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// 文件大小(bytes)
|
||||
// Size returns the size of file specified by <path> in byte.
|
||||
func Size(path string) int64 {
|
||||
s, e := os.Stat(path)
|
||||
if e != nil {
|
||||
@ -20,12 +20,12 @@ func Size(path string) int64 {
|
||||
return s.Size()
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
// ReadableSize formats size of file given by <path>, for more human readable.
|
||||
func ReadableSize(path string) string {
|
||||
return FormatSize(float64(Size(path)))
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
// FormatSize formats size <raw> for more human readable.
|
||||
func FormatSize(raw float64) string {
|
||||
var t float64 = 1024
|
||||
var d float64 = 1
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// 文件修改时间(时间戳,秒)
|
||||
// MTime returns the modification time of file given by <path> in second.
|
||||
func MTime(path string) int64 {
|
||||
s, e := os.Stat(path)
|
||||
if e != nil {
|
||||
@ -19,7 +19,7 @@ func MTime(path string) int64 {
|
||||
return s.ModTime().Unix()
|
||||
}
|
||||
|
||||
// 文件修改时间(时间戳,毫秒)
|
||||
// MTimeMillisecond returns the modification time of file given by <path> in millisecond.
|
||||
func MTimeMillisecond(path string) int64 {
|
||||
s, e := os.Stat(path)
|
||||
if e != nil {
|
||||
|
||||
@ -10,9 +10,8 @@
|
||||
package glog
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/internal/cmdenv"
|
||||
"io"
|
||||
"github.com/gogf/gf/g/internal/cmdenv"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -28,9 +27,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Default level for log
|
||||
defaultLevel = gtype.NewInt(LEVEL_ALL)
|
||||
|
||||
// Default logger object, for package method usage
|
||||
logger = New()
|
||||
)
|
||||
@ -44,6 +40,12 @@ func SetPath(path string) {
|
||||
logger.SetPath(path)
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
// It returns empty string if no directory path set.
|
||||
func GetPath() string {
|
||||
return logger.GetPath()
|
||||
}
|
||||
|
||||
// SetFile sets the file name <pattern> for file logging.
|
||||
// Datetime pattern can be used in <pattern>, eg: access-{Ymd}.log.
|
||||
// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
|
||||
@ -54,7 +56,11 @@ func SetFile(pattern string) {
|
||||
// SetLevel sets the default logging level.
|
||||
func SetLevel(level int) {
|
||||
logger.SetLevel(level)
|
||||
defaultLevel.Set(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the default logging level value.
|
||||
func GetLevel() int {
|
||||
return logger.GetLevel()
|
||||
}
|
||||
|
||||
// SetWriter sets the customized logging <writer> for logging.
|
||||
@ -71,26 +77,36 @@ func GetWriter() io.Writer {
|
||||
return logger.GetWriter()
|
||||
}
|
||||
|
||||
// GetLevel returns the default logging level value.
|
||||
func GetLevel() int {
|
||||
return defaultLevel.Val()
|
||||
}
|
||||
|
||||
// SetDebug enables/disables the debug level for default logger.
|
||||
// The debug level is enbaled in default.
|
||||
func SetDebug(debug bool) {
|
||||
logger.SetDebug(debug)
|
||||
}
|
||||
|
||||
// SetStdPrint sets whether ouptput the logging contents to stdout, which is false in default.
|
||||
func SetStdPrint(open bool) {
|
||||
logger.SetStdPrint(open)
|
||||
// SetStdoutPrint sets whether ouptput the logging contents to stdout, which is false in default.
|
||||
func SetStdoutPrint(enabled bool) {
|
||||
logger.SetStdoutPrint(enabled)
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
// It returns empty string if no directory path set.
|
||||
func GetPath() string {
|
||||
return logger.GetPath()
|
||||
// SetHeaderPrint sets whether output header of the logging contents, which is true in default.
|
||||
func SetHeaderPrint(enabled bool) {
|
||||
logger.SetHeaderPrint(enabled)
|
||||
}
|
||||
|
||||
// SetPrefix sets prefix string for every logging content.
|
||||
// Prefix is part of header, which means if header output is shut, no prefix will be output.
|
||||
func SetPrefix(prefix string) {
|
||||
logger.SetPrefix(prefix)
|
||||
}
|
||||
|
||||
// SetFlags sets extra flags for logging output features.
|
||||
func SetFlags(flags int) {
|
||||
logger.SetFlags(flags)
|
||||
}
|
||||
|
||||
// GetFlags returns the flags of logger.
|
||||
func GetFlags() int {
|
||||
return logger.GetFlags()
|
||||
}
|
||||
|
||||
// PrintBacktrace prints the caller backtrace,
|
||||
@ -109,166 +125,3 @@ func GetBacktrace(skip...int) string {
|
||||
func SetBacktrace(enabled bool) {
|
||||
logger.SetBacktrace(enabled)
|
||||
}
|
||||
|
||||
// To is a chaining function,
|
||||
// which redirects current logging content output to the sepecified <writer>.
|
||||
func To(writer io.Writer) *Logger {
|
||||
return logger.To(writer)
|
||||
}
|
||||
|
||||
// Path is a chaining function,
|
||||
// which sets the directory path to <path> for current logging content output.
|
||||
func Path(path string) *Logger {
|
||||
return logger.Path(path)
|
||||
}
|
||||
|
||||
// Cat is a chaining function,
|
||||
// which sets the category to <category> for current logging content output.
|
||||
func Cat(category string) *Logger {
|
||||
return logger.Cat(category)
|
||||
}
|
||||
|
||||
// File is a chaining function,
|
||||
// which sets file name <pattern> for the current logging content output.
|
||||
func File(pattern string) *Logger {
|
||||
return logger.File(pattern)
|
||||
}
|
||||
|
||||
// Level is a chaining function,
|
||||
// which sets logging level for the current logging content output.
|
||||
func Level(level int) *Logger {
|
||||
return logger.Level(level)
|
||||
}
|
||||
|
||||
// Backtrace is a chaining function,
|
||||
// which sets backtrace options for the current logging content output .
|
||||
func Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger.Backtrace(enabled, skip...)
|
||||
}
|
||||
|
||||
// StdPrint is a chaining function,
|
||||
// which enables/disables stdout for the current logging content output.
|
||||
func StdPrint(enabled bool) *Logger {
|
||||
return logger.StdPrint(enabled)
|
||||
}
|
||||
|
||||
// Header is a chaining function,
|
||||
// which enables/disables log header for the current logging content output.
|
||||
func Header(enabled bool) *Logger {
|
||||
return logger.Header(enabled)
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
logger.Print(v ...)
|
||||
}
|
||||
|
||||
func Printf(format string, v ...interface{}) {
|
||||
logger.Printf(format, v ...)
|
||||
}
|
||||
|
||||
func Println(v ...interface{}) {
|
||||
logger.Println(v ...)
|
||||
}
|
||||
|
||||
func Printfln(format string, v ...interface{}) {
|
||||
logger.Printfln(format, v ...)
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func Fatal(v ...interface{}) {
|
||||
logger.Fatal(v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
logger.Fatalf(format, v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func Fatalfln(format string, v ...interface{}) {
|
||||
logger.Fatalfln(format, v ...)
|
||||
}
|
||||
|
||||
func Panic(v ...interface{}) {
|
||||
logger.Panic(v ...)
|
||||
}
|
||||
|
||||
func Panicf(format string, v ...interface{}) {
|
||||
logger.Panicf(format, v ...)
|
||||
}
|
||||
|
||||
func Panicfln(format string, v ...interface{}) {
|
||||
logger.Panicfln(format, v ...)
|
||||
}
|
||||
|
||||
func Info(v ...interface{}) {
|
||||
logger.Info(v...)
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
logger.Debug(v...)
|
||||
}
|
||||
|
||||
func Notice(v ...interface{}) {
|
||||
logger.Notice(v...)
|
||||
}
|
||||
|
||||
func Warning(v ...interface{}) {
|
||||
logger.Warning(v...)
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
logger.Error(v...)
|
||||
}
|
||||
|
||||
func Critical(v ...interface{}) {
|
||||
logger.Critical(v...)
|
||||
}
|
||||
|
||||
func Infof(format string, v ...interface{}) {
|
||||
logger.Infof(format, v...)
|
||||
}
|
||||
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
logger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func Noticef(format string, v ...interface{}) {
|
||||
logger.Noticef(format, v...)
|
||||
}
|
||||
|
||||
func Warningf(format string, v ...interface{}) {
|
||||
logger.Warningf(format, v...)
|
||||
}
|
||||
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
logger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
func Criticalf(format string, v ...interface{}) {
|
||||
logger.Criticalf(format, v...)
|
||||
}
|
||||
|
||||
func Infofln(format string, v ...interface{}) {
|
||||
logger.Infofln(format, v...)
|
||||
}
|
||||
|
||||
func Debugfln(format string, v ...interface{}) {
|
||||
logger.Debugfln(format, v...)
|
||||
}
|
||||
|
||||
func Noticefln(format string, v ...interface{}) {
|
||||
logger.Noticefln(format, v...)
|
||||
}
|
||||
|
||||
func Warningfln(format string, v ...interface{}) {
|
||||
logger.Warningfln(format, v...)
|
||||
}
|
||||
|
||||
func Errorfln(format string, v ...interface{}) {
|
||||
logger.Errorfln(format, v...)
|
||||
}
|
||||
|
||||
func Criticalfln(format string, v ...interface{}) {
|
||||
logger.Criticalfln(format, v...)
|
||||
}
|
||||
|
||||
162
g/os/glog/glog_api.go
Normal file
162
g/os/glog/glog_api.go
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package glog
|
||||
|
||||
// Print prints <v> with newline using fmt.Sprintln.
|
||||
// The param <v> can be multiple variables.
|
||||
func Print(v ...interface{}) {
|
||||
logger.Print(v ...)
|
||||
}
|
||||
|
||||
// Printf prints <v> with format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
logger.Printf(format, v ...)
|
||||
}
|
||||
|
||||
// See Print.
|
||||
func Println(v ...interface{}) {
|
||||
logger.Println(v ...)
|
||||
}
|
||||
|
||||
// Printf prints <v> with newline and format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
func Printfln(format string, v ...interface{}) {
|
||||
logger.Printfln(format, v ...)
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func Fatal(v ...interface{}) {
|
||||
logger.Fatal(v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
logger.Fatalf(format, v ...)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func Fatalfln(format string, v ...interface{}) {
|
||||
logger.Fatalfln(format, v ...)
|
||||
}
|
||||
|
||||
// Panic prints the logging content with [PANI] header and newline, then panics.
|
||||
func Panic(v ...interface{}) {
|
||||
logger.Panic(v ...)
|
||||
}
|
||||
|
||||
// Panicf prints the logging content with [PANI] header and custom format, then panics.
|
||||
func Panicf(format string, v ...interface{}) {
|
||||
logger.Panicf(format, v ...)
|
||||
}
|
||||
|
||||
// Panicfln prints the logging content with [PANI] header, newline and custom format, then panics.
|
||||
func Panicfln(format string, v ...interface{}) {
|
||||
logger.Panicfln(format, v ...)
|
||||
}
|
||||
|
||||
// Info prints the logging content with [INFO] header and newline.
|
||||
func Info(v ...interface{}) {
|
||||
logger.Info(v...)
|
||||
}
|
||||
|
||||
// Infof prints the logging content with [INFO] header and custom format.
|
||||
func Infof(format string, v ...interface{}) {
|
||||
logger.Infof(format, v...)
|
||||
}
|
||||
|
||||
// Infofln prints the logging content with [INFO] header, newline and custom format.
|
||||
func Infofln(format string, v ...interface{}) {
|
||||
logger.Infofln(format, v...)
|
||||
}
|
||||
|
||||
// Debug prints the logging content with [DEBU] header and newline.
|
||||
func Debug(v ...interface{}) {
|
||||
logger.Debug(v...)
|
||||
}
|
||||
|
||||
// Debugf prints the logging content with [DEBU] header and custom format.
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
logger.Debugf(format, v...)
|
||||
}
|
||||
|
||||
// Debugfln prints the logging content with [DEBU] header, newline and custom format.
|
||||
func Debugfln(format string, v ...interface{}) {
|
||||
logger.Debugfln(format, v...)
|
||||
}
|
||||
|
||||
// Notice prints the logging content with [NOTI] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Notice(v ...interface{}) {
|
||||
logger.Notice(v...)
|
||||
}
|
||||
|
||||
// Noticef prints the logging content with [NOTI] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Noticef(format string, v ...interface{}) {
|
||||
logger.Noticef(format, v...)
|
||||
}
|
||||
|
||||
// Noticefln prints the logging content with [NOTI] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Noticefln(format string, v ...interface{}) {
|
||||
logger.Noticefln(format, v...)
|
||||
}
|
||||
|
||||
// Warning prints the logging content with [WARN] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Warning(v ...interface{}) {
|
||||
logger.Warning(v...)
|
||||
}
|
||||
|
||||
// Warningf prints the logging content with [WARN] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Warningf(format string, v ...interface{}) {
|
||||
logger.Warningf(format, v...)
|
||||
}
|
||||
|
||||
// Warningfln prints the logging content with [WARN] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Warningfln(format string, v ...interface{}) {
|
||||
logger.Warningfln(format, v...)
|
||||
}
|
||||
|
||||
// Error prints the logging content with [ERRO] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Error(v ...interface{}) {
|
||||
logger.Error(v...)
|
||||
}
|
||||
|
||||
// Errorf prints the logging content with [ERRO] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
logger.Errorf(format, v...)
|
||||
}
|
||||
|
||||
// Errorfln prints the logging content with [ERRO] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Errorfln(format string, v ...interface{}) {
|
||||
logger.Errorfln(format, v...)
|
||||
}
|
||||
|
||||
// Critical prints the logging content with [CRIT] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Critical(v ...interface{}) {
|
||||
logger.Critical(v...)
|
||||
}
|
||||
|
||||
// Criticalf prints the logging content with [CRIT] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Criticalf(format string, v ...interface{}) {
|
||||
logger.Criticalf(format, v...)
|
||||
}
|
||||
|
||||
// Criticalfln prints the logging content with [CRIT] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func Criticalfln(format string, v ...interface{}) {
|
||||
logger.Criticalfln(format, v...)
|
||||
}
|
||||
75
g/os/glog/glog_chaining.go
Normal file
75
g/os/glog/glog_chaining.go
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package glog
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// To is a chaining function,
|
||||
// which redirects current logging content output to the sepecified <writer>.
|
||||
func To(writer io.Writer) *Logger {
|
||||
return logger.To(writer)
|
||||
}
|
||||
|
||||
// Path is a chaining function,
|
||||
// which sets the directory path to <path> for current logging content output.
|
||||
func Path(path string) *Logger {
|
||||
return logger.Path(path)
|
||||
}
|
||||
|
||||
// Cat is a chaining function,
|
||||
// which sets the category to <category> for current logging content output.
|
||||
func Cat(category string) *Logger {
|
||||
return logger.Cat(category)
|
||||
}
|
||||
|
||||
// File is a chaining function,
|
||||
// which sets file name <pattern> for the current logging content output.
|
||||
func File(pattern string) *Logger {
|
||||
return logger.File(pattern)
|
||||
}
|
||||
|
||||
// Level is a chaining function,
|
||||
// which sets logging level for the current logging content output.
|
||||
func Level(level int) *Logger {
|
||||
return logger.Level(level)
|
||||
}
|
||||
|
||||
// Skip is a chaining function,
|
||||
// which sets backtrace skip for the current logging content output.
|
||||
// It also affects the caller file path checks when line number printing enabled.
|
||||
func Skip(skip int) *Logger {
|
||||
return logger.Skip(skip)
|
||||
}
|
||||
|
||||
// Backtrace is a chaining function,
|
||||
// which sets backtrace options for the current logging content output .
|
||||
func Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger.Backtrace(enabled, skip...)
|
||||
}
|
||||
|
||||
// StdPrint is a chaining function,
|
||||
// which enables/disables stdout for the current logging content output.
|
||||
// It's enabled in default.
|
||||
func Stdout(enabled...bool) *Logger {
|
||||
return logger.Stdout(enabled...)
|
||||
}
|
||||
|
||||
// Header is a chaining function,
|
||||
// which enables/disables log header for the current logging content output.
|
||||
// It's enabled in default.
|
||||
func Header(enabled...bool) *Logger {
|
||||
return logger.Header(enabled...)
|
||||
}
|
||||
|
||||
// Line is a chaining function,
|
||||
// which enables/disables printing its caller file along with its line number.
|
||||
// The param <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23.
|
||||
func Line(long...bool) *Logger {
|
||||
return logger.Line(long...)
|
||||
}
|
||||
@ -9,9 +9,9 @@
|
||||
package glog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/os/gfpool"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
@ -20,21 +20,21 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
mu sync.RWMutex
|
||||
pr *Logger // Parent logger.
|
||||
writer io.Writer // Customized io.Writer.
|
||||
path *gtype.String // Logging directory path.
|
||||
file *gtype.String // Format for logging file.
|
||||
level *gtype.Int // Output level.
|
||||
btSkip *gtype.Int // Skip count for backtrace.
|
||||
btStatus *gtype.Int // Backtrace status(1: enabled - default; 0: disabled)
|
||||
printHeader *gtype.Bool // Print header or not(true in default).
|
||||
alsoStdPrint *gtype.Bool // Output to stdout or not(true in default).
|
||||
parent *Logger // Parent logger.
|
||||
writer io.Writer // Customized io.Writer.
|
||||
flags int // Extra flags for logging output features.
|
||||
path string // Logging directory path.
|
||||
file string // Format for logging file.
|
||||
level int // Output level.
|
||||
prefix string // Prefix string for every logging content.
|
||||
btSkip int // Skip count for backtrace.
|
||||
btStatus int // Backtrace status(1: enabled - default; 0: disabled)
|
||||
headerPrint bool // Print header or not(true in default).
|
||||
stdoutPrint bool // Output to stdout or not(true in default).
|
||||
}
|
||||
|
||||
const (
|
||||
@ -44,11 +44,18 @@ const (
|
||||
gDEFAULT_FPOOL_EXPIRE = 60000
|
||||
)
|
||||
|
||||
const (
|
||||
F_FILE_LONG = 1 << iota // Print full file name and line number: /a/b/c/d.go:23.
|
||||
F_FILE_SHORT // Print final file name element and line number: d.go:23. overrides F_FILE_LONG.
|
||||
F_TIME_DATE // Print the date in the local time zone: 2009-01-23.
|
||||
F_TIME_TIME // Print the time in the local time zone: 01:23:23.
|
||||
F_TIME_MILLI // Print the time with milliseconds in the local time zone: 01:23:23.675.
|
||||
F_TIME_STD = F_TIME_DATE | F_TIME_MILLI
|
||||
)
|
||||
|
||||
var (
|
||||
// Default line break.
|
||||
ln = "\n"
|
||||
// Mutex to ensure log output sequence.
|
||||
stdMu = sync.RWMutex{}
|
||||
ln = "\n"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -61,16 +68,12 @@ func init() {
|
||||
// New creates and returns a custom logger.
|
||||
func New() *Logger {
|
||||
logger := &Logger {
|
||||
path : gtype.NewString(),
|
||||
file : gtype.NewString(gDEFAULT_FILE_FORMAT),
|
||||
level : gtype.NewInt(defaultLevel.Val()),
|
||||
btSkip : gtype.NewInt(),
|
||||
btStatus : gtype.NewInt(1),
|
||||
printHeader : gtype.NewBool(true),
|
||||
alsoStdPrint : gtype.NewBool(true),
|
||||
}
|
||||
logger.writer = &Writer {
|
||||
logger : logger,
|
||||
file : gDEFAULT_FILE_FORMAT,
|
||||
flags : F_TIME_STD,
|
||||
level : LEVEL_ALL,
|
||||
btStatus : 1,
|
||||
headerPrint : true,
|
||||
stdoutPrint : true,
|
||||
}
|
||||
return logger
|
||||
}
|
||||
@ -78,53 +81,62 @@ func New() *Logger {
|
||||
// Clone returns a new logger, which is the clone the current logger.
|
||||
func (l *Logger) Clone() *Logger {
|
||||
logger := &Logger {
|
||||
pr : l,
|
||||
path : l.path.Clone(),
|
||||
file : l.file.Clone(),
|
||||
level : l.level.Clone(),
|
||||
btSkip : l.btSkip.Clone(),
|
||||
btStatus : l.btStatus.Clone(),
|
||||
printHeader : l.printHeader.Clone(),
|
||||
alsoStdPrint : l.alsoStdPrint.Clone(),
|
||||
parent : l,
|
||||
path : l.path,
|
||||
file : l.file,
|
||||
level : l.level,
|
||||
flags : l.flags,
|
||||
prefix : l.prefix,
|
||||
btSkip : l.btSkip,
|
||||
btStatus : l.btStatus,
|
||||
headerPrint : l.headerPrint,
|
||||
stdoutPrint : l.stdoutPrint,
|
||||
}
|
||||
logger.writer = &Writer {
|
||||
logger : logger,
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// SetLevel sets the logging level.
|
||||
func (l *Logger) SetLevel(level int) {
|
||||
l.level.Set(level)
|
||||
l.level = level
|
||||
}
|
||||
|
||||
// GetLevel returns the logging level value.
|
||||
func (l *Logger) GetLevel() int {
|
||||
return l.level.Val()
|
||||
return l.level
|
||||
}
|
||||
|
||||
// SetDebug enables/disables the debug level for logger.
|
||||
// The debug level is enabled in default.
|
||||
func (l *Logger) SetDebug(debug bool) {
|
||||
if debug {
|
||||
l.level.Set(l.level.Val() | LEVEL_DEBU)
|
||||
l.level = l.level | LEVEL_DEBU
|
||||
} else {
|
||||
l.level.Set(l.level.Val() & ^LEVEL_DEBU)
|
||||
l.level = l.level & ^LEVEL_DEBU
|
||||
}
|
||||
}
|
||||
|
||||
// SetFlags sets extra flags for logging output features.
|
||||
func (l *Logger) SetFlags(flags int) {
|
||||
l.flags = flags
|
||||
}
|
||||
|
||||
// GetFlags returns the flags of logger.
|
||||
func (l *Logger) GetFlags() int {
|
||||
return l.flags
|
||||
}
|
||||
|
||||
// SetBacktrace enables/disables the backtrace feature in failure logging outputs.
|
||||
func (l *Logger) SetBacktrace(enabled bool) {
|
||||
if enabled {
|
||||
l.btStatus.Set(1)
|
||||
l.btStatus = 1
|
||||
} else {
|
||||
l.btStatus.Set(0)
|
||||
l.btStatus = 0
|
||||
}
|
||||
}
|
||||
|
||||
// SetBacktraceSkip sets the backtrace offset from the end point.
|
||||
func (l *Logger) SetBacktraceSkip(skip int) {
|
||||
l.btSkip.Set(skip)
|
||||
l.btSkip = skip
|
||||
}
|
||||
|
||||
// SetWriter sets the customized logging <writer> for logging.
|
||||
@ -132,26 +144,21 @@ func (l *Logger) SetBacktraceSkip(skip int) {
|
||||
// Developer can use customized logging <writer> to redirect logging output to another service,
|
||||
// eg: kafka, mysql, mongodb, etc.
|
||||
func (l *Logger) SetWriter(writer io.Writer) {
|
||||
l.mu.Lock()
|
||||
l.writer = writer
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetWriter returns the customized writer object, which implements the io.Writer interface.
|
||||
// It returns a default writer if no customized writer set.
|
||||
// It returns nil if no writer previously set.
|
||||
func (l *Logger) GetWriter() io.Writer {
|
||||
l.mu.RLock()
|
||||
r := l.writer
|
||||
l.mu.RUnlock()
|
||||
return r
|
||||
return l.writer
|
||||
}
|
||||
|
||||
// getFilePointer returns the file pinter for file logging.
|
||||
// It returns nil if file logging is disabled, or file opening fails.
|
||||
func (l *Logger) getFilePointer() *gfpool.File {
|
||||
if path := l.path.Val(); path != "" {
|
||||
if path := l.path; path != "" {
|
||||
// Content containing "{}" in the file name is formatted using gtime
|
||||
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.file.Val(), func(s string) string {
|
||||
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.file, func(s string) string {
|
||||
return gtime.Now().Format(strings.Trim(s, "{}"))
|
||||
})
|
||||
// Create path if it does not exist。
|
||||
@ -161,8 +168,11 @@ func (l *Logger) getFilePointer() *gfpool.File {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
fpath := path + gfile.Separator + file
|
||||
if fp, err := gfpool.Open(fpath, gDEFAULT_FILE_POOL_FLAGS, gDEFAULT_FPOOL_PERM, gDEFAULT_FPOOL_EXPIRE); err == nil {
|
||||
if fp, err := gfpool.Open(
|
||||
path + gfile.Separator + file,
|
||||
gDEFAULT_FILE_POOL_FLAGS,
|
||||
gDEFAULT_FPOOL_PERM,
|
||||
gDEFAULT_FPOOL_EXPIRE); err == nil {
|
||||
return fp
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
@ -182,69 +192,73 @@ func (l *Logger) SetPath(path string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l.path.Set(strings.TrimRight(path, gfile.Separator))
|
||||
l.path = strings.TrimRight(path, gfile.Separator)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
// It returns empty string if no directory path set.
|
||||
func (l *Logger) GetPath() string {
|
||||
return l.path.Val()
|
||||
return l.path
|
||||
}
|
||||
|
||||
// SetFile sets the file name <pattern> for file logging.
|
||||
// Datetime pattern can be used in <pattern>, eg: access-{Ymd}.log.
|
||||
// The default file name pattern is: Y-m-d.log, eg: 2018-01-01.log
|
||||
func (l *Logger) SetFile(pattern string) {
|
||||
l.file.Set(pattern)
|
||||
l.file = pattern
|
||||
}
|
||||
|
||||
// SetStdPrint sets whether output the logging contents to stdout, which is false in default.
|
||||
func (l *Logger) SetStdPrint(enabled bool) {
|
||||
l.alsoStdPrint.Set(enabled)
|
||||
// SetStdoutPrint sets whether output the logging contents to stdout, which is true in default.
|
||||
func (l *Logger) SetStdoutPrint(enabled bool) {
|
||||
l.stdoutPrint = enabled
|
||||
}
|
||||
|
||||
// SetHeaderPrint sets whether output header of the logging contents, which is true in default.
|
||||
func (l *Logger) SetHeaderPrint(enabled bool) {
|
||||
l.headerPrint = enabled
|
||||
}
|
||||
|
||||
// SetPrefix sets prefix string for every logging content.
|
||||
// Prefix is part of header, which means if header output is shut, no prefix will be output.
|
||||
func (l *Logger) SetPrefix(prefix string) {
|
||||
l.prefix = prefix
|
||||
}
|
||||
|
||||
// print prints <s> to defined writer, logging file or passed <std>.
|
||||
// It internally uses memory lock for file logging to ensure logging sequence.
|
||||
func (l *Logger) print(std io.Writer, s string) {
|
||||
// Customized writer has the most high priority.
|
||||
if l.printHeader.Val() {
|
||||
// Custom writer has the most high priority.
|
||||
if l.headerPrint {
|
||||
s = l.format(s)
|
||||
}
|
||||
writer := l.GetWriter()
|
||||
if _, ok := writer.(*Writer); ok {
|
||||
if l.writer == nil {
|
||||
if f := l.getFilePointer(); f != nil {
|
||||
defer f.Close()
|
||||
if _, err := io.WriteString(f, s); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
// Also output to stdout?
|
||||
if l.alsoStdPrint.Val() {
|
||||
l.doStdLockPrint(std, s)
|
||||
// Allow output to stdout?
|
||||
if l.stdoutPrint {
|
||||
if _, err := std.Write([]byte(s)); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
l.doStdLockPrint(writer, s)
|
||||
if _, err := l.writer.Write([]byte(s)); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doStdLockPrint prints <s> to <std> concurrent-safely.
|
||||
func (l *Logger) doStdLockPrint(std io.Writer, s string) {
|
||||
stdMu.Lock()
|
||||
if _, err := std.Write([]byte(s)); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
stdMu.Unlock()
|
||||
}
|
||||
|
||||
// stdPrint prints content <s> without backtrace.
|
||||
func (l *Logger) stdPrint(s string) {
|
||||
// printStd prints content <s> without backtrace.
|
||||
func (l *Logger) printStd(s string) {
|
||||
l.print(os.Stdout, s)
|
||||
}
|
||||
|
||||
// stdPrint prints content <s> with backtrace check.
|
||||
func (l *Logger) errPrint(s string) {
|
||||
if l.btStatus.Val() == 1 {
|
||||
// printStd prints content <s> with backtrace check.
|
||||
func (l *Logger) printErr(s string) {
|
||||
if l.btStatus == 1 {
|
||||
s = l.appendBacktrace(s)
|
||||
}
|
||||
// In matter of sequence, do not use stderr here, but use the same stdout.
|
||||
@ -283,10 +297,9 @@ func (l *Logger) GetBacktrace(skip...int) string {
|
||||
customSkip = skip[0]
|
||||
}
|
||||
backtrace := ""
|
||||
index := 1
|
||||
from := 0
|
||||
// 首先定位业务文件开始位置
|
||||
for i := 0; i < 10; i++ {
|
||||
// Find the caller position exclusive of the glog file.
|
||||
for i := 0; i < 100; i++ {
|
||||
if _, file, _, ok := runtime.Caller(i); ok {
|
||||
if !gregex.IsMatchString("/g/os/glog/glog.+$", file) {
|
||||
from = i
|
||||
@ -294,11 +307,11 @@ func (l *Logger) GetBacktrace(skip...int) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 从业务文件开始位置根据自定义的skip开始backtrace
|
||||
// Find the true caller file path using custom skip.
|
||||
index := 1
|
||||
goRoot := runtime.GOROOT()
|
||||
for i := from + customSkip + l.btSkip.Val(); i < 10000; i++ {
|
||||
for i := from + customSkip + l.btSkip; i < 10000; i++ {
|
||||
if _, file, cline, ok := runtime.Caller(i); ok && file != "" {
|
||||
// 不打印出go源码路径及glog包文件路径,日志打印必须从业务源码文件开始,且从glog包文件开始检索
|
||||
if (goRoot == "" || !gregex.IsMatchString("^" + goRoot, file)) && !gregex.IsMatchString(`<autogenerated>`, file) {
|
||||
backtrace += fmt.Sprintf(`%d. %s:%d%s`, index, file, cline, ln)
|
||||
index++
|
||||
@ -310,171 +323,68 @@ func (l *Logger) GetBacktrace(skip...int) string {
|
||||
return backtrace
|
||||
}
|
||||
|
||||
func (l *Logger) format(s string) string {
|
||||
return time.Now().Format("2006-01-02 15:04:05.000 ") + s
|
||||
// getLongFile returns the absolute file path along with its line number of the caller.
|
||||
func (l *Logger) getLongFile() string {
|
||||
from := 0
|
||||
// Find the caller position exclusive of the glog file.
|
||||
for i := 0; i < 100; i++ {
|
||||
if _, file, line, ok := runtime.Caller(i); ok {
|
||||
if !gregex.IsMatchString("/g/os/glog/glog.+$", file) {
|
||||
from = i
|
||||
break
|
||||
return fmt.Sprintf(`%s:%d`, file, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find the true caller file path using custom skip.
|
||||
goRoot := runtime.GOROOT()
|
||||
for i := from + l.btSkip; i < 10000; i++ {
|
||||
if _, file, line, ok := runtime.Caller(i); ok && file != "" {
|
||||
if (goRoot == "" || !gregex.IsMatchString("^" + goRoot, file)) && !gregex.IsMatchString(`<autogenerated>`, file) {
|
||||
return fmt.Sprintf(`%s:%d`, file, line)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (l *Logger) Print(v ...interface{}) {
|
||||
l.stdPrint(fmt.Sprintln(v...))
|
||||
|
||||
// format formats the content according the flags.
|
||||
func (l *Logger) format(content string) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
// Time.
|
||||
timeFormat := ""
|
||||
if l.flags & F_TIME_DATE > 0 {
|
||||
timeFormat += "2006-01-02 "
|
||||
}
|
||||
if l.flags & F_TIME_TIME > 0 {
|
||||
timeFormat += "15:04:05 "
|
||||
}
|
||||
if l.flags & F_TIME_MILLI > 0 {
|
||||
timeFormat += "15:04:05.000 "
|
||||
}
|
||||
if len(timeFormat) > 0 {
|
||||
buffer.WriteString(time.Now().Format(timeFormat))
|
||||
}
|
||||
// Caller path.
|
||||
callerPath := ""
|
||||
if l.flags & F_FILE_LONG > 0 {
|
||||
callerPath = l.getLongFile() + ": "
|
||||
}
|
||||
if l.flags & F_FILE_SHORT > 0 {
|
||||
callerPath = gfile.Basename(l.getLongFile()) + ": "
|
||||
}
|
||||
if len(callerPath) > 0 {
|
||||
buffer.WriteString(callerPath)
|
||||
}
|
||||
// Prefix.
|
||||
if len(l.prefix) > 0 {
|
||||
buffer.WriteString(l.prefix + " ")
|
||||
}
|
||||
// Content.
|
||||
buffer.WriteString(content)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||
l.stdPrint(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func (l *Logger) Println(v ...interface{}) {
|
||||
l.stdPrint(fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
func (l *Logger) Printfln(format string, v ...interface{}) {
|
||||
l.stdPrint(fmt.Sprintf(format + ln, v...))
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func (l *Logger) Fatal(v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintln(v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintf(format, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func (l *Logger) Fatalfln(format string, v ...interface{}) {
|
||||
l.errPrint("[FATA] " + fmt.Sprintf(format + ln, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Panic(v ...interface{}) {
|
||||
s := fmt.Sprintln(v...)
|
||||
l.errPrint("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
func (l *Logger) Panicf(format string, v ...interface{}) {
|
||||
s := fmt.Sprintf(format, v...)
|
||||
l.errPrint("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
func (l *Logger) Panicfln(format string, v ...interface{}) {
|
||||
s := fmt.Sprintf(format + ln, v...)
|
||||
l.errPrint("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
func (l *Logger) Info(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.stdPrint("[INFO] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.stdPrint("[INFO] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Infofln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.stdPrint("[INFO] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.stdPrint("[DEBU] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debugfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.stdPrint("[DEBU] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Notice(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.errPrint("[NOTI] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Noticef(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.errPrint("[NOTI] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Noticefln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.errPrint("[NOTI] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Warning(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.errPrint("[WARN] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Warningf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.errPrint("[WARN] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Warningfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.errPrint("[WARN] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Error(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.errPrint("[ERRO] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.errPrint("[ERRO] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Errorfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.errPrint("[ERRO] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Critical(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.errPrint("[CRIT] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Criticalf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.errPrint("[CRIT] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Criticalfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.errPrint("[CRIT] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// checkLevel checks whether the given <level> could be output.
|
||||
func (l *Logger) checkLevel(level int) bool {
|
||||
return l.level.Val() & level > 0
|
||||
}
|
||||
217
g/os/glog/glog_logger_api.go
Normal file
217
g/os/glog/glog_logger_api.go
Normal file
@ -0,0 +1,217 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package glog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Print prints <v> with newline using fmt.Sprintln.
|
||||
// The param <v> can be multiple variables.
|
||||
func (l *Logger) Print(v ...interface{}) {
|
||||
l.printStd(fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Printf prints <v> with format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||
l.printStd(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// See Print.
|
||||
func (l *Logger) Println(v ...interface{}) {
|
||||
l.Print(v...)
|
||||
}
|
||||
|
||||
// Printfln prints <v> with newline and format <format> using fmt.Sprintf.
|
||||
// The param <v> can be multiple variables.
|
||||
func (l *Logger) Printfln(format string, v ...interface{}) {
|
||||
l.printStd(fmt.Sprintf(format + ln, v...))
|
||||
}
|
||||
|
||||
// Fatal prints the logging content with [FATA] header and newline, then exit the current process.
|
||||
func (l *Logger) Fatal(v ...interface{}) {
|
||||
l.printErr("[FATA] " + fmt.Sprintln(v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf prints the logging content with [FATA] header and custom format, then exit the current process.
|
||||
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
||||
l.printErr("[FATA] " + fmt.Sprintf(format, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalfln prints the logging content with [FATA] header, custom format and newline, then exit the current process.
|
||||
func (l *Logger) Fatalfln(format string, v ...interface{}) {
|
||||
l.printErr("[FATA] " + fmt.Sprintf(format + ln, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Panic prints the logging content with [PANI] header and newline, then panics.
|
||||
func (l *Logger) Panic(v ...interface{}) {
|
||||
s := fmt.Sprintln(v...)
|
||||
l.printErr("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Panicf prints the logging content with [PANI] header and custom format, then panics.
|
||||
func (l *Logger) Panicf(format string, v ...interface{}) {
|
||||
s := fmt.Sprintf(format, v...)
|
||||
l.printErr("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Panicfln prints the logging content with [PANI] header, newline and custom format, then panics.
|
||||
func (l *Logger) Panicfln(format string, v ...interface{}) {
|
||||
s := fmt.Sprintf(format + ln, v...)
|
||||
l.printErr("[PANI] " + s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Info prints the logging content with [INFO] header and newline.
|
||||
func (l *Logger) Info(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.printStd("[INFO] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Infof prints the logging content with [INFO] header and custom format.
|
||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.printStd("[INFO] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Infofln prints the logging content with [INFO] header, newline and custom format.
|
||||
func (l *Logger) Infofln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_INFO) {
|
||||
l.printStd("[INFO] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// Debug prints the logging content with [DEBU] header and newline.
|
||||
func (l *Logger) Debug(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.printStd("[DEBU] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debugf prints the logging content with [DEBU] header and custom format.
|
||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.printStd("[DEBU] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debugfln prints the logging content with [DEBU] header, newline and custom format.
|
||||
func (l *Logger) Debugfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_DEBU) {
|
||||
l.printStd("[DEBU] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// Notice prints the logging content with [NOTI] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Notice(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.printErr("[NOTI] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Noticef prints the logging content with [NOTI] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Noticef(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.printErr("[NOTI] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Noticefln prints the logging content with [NOTI] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Noticefln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_NOTI) {
|
||||
l.printErr("[NOTI] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// Warning prints the logging content with [WARN] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Warning(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.printErr("[WARN] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Warningf prints the logging content with [WARN] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Warningf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.printErr("[WARN] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Warningfln prints the logging content with [WARN] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Warningfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_WARN) {
|
||||
l.printErr("[WARN] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// Error prints the logging content with [ERRO] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Error(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.printErr("[ERRO] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf prints the logging content with [ERRO] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.printErr("[ERRO] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Errorfln prints the logging content with [ERRO] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Errorfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_ERRO) {
|
||||
l.printErr("[ERRO] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// Critical prints the logging content with [CRIT] header and newline.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Critical(v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.printErr("[CRIT] " + fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Criticalf prints the logging content with [CRIT] header and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Criticalf(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.printErr("[CRIT] " + fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Criticalfln prints the logging content with [CRIT] header, newline and custom format.
|
||||
// It also prints caller backtrace info if backtrace feature is enabled.
|
||||
func (l *Logger) Criticalfln(format string, v ...interface{}) {
|
||||
if l.checkLevel(LEVEL_CRIT) {
|
||||
l.printErr("[CRIT] " + fmt.Sprintf(format, v...) + ln)
|
||||
}
|
||||
}
|
||||
|
||||
// checkLevel checks whether the given <level> could be output.
|
||||
func (l *Logger) checkLevel(level int) bool {
|
||||
return l.level & level > 0
|
||||
}
|
||||
@ -15,7 +15,7 @@ import (
|
||||
// which redirects current logging content output to the specified <writer>.
|
||||
func (l *Logger) To(writer io.Writer) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
@ -28,7 +28,7 @@ func (l *Logger) To(writer io.Writer) *Logger {
|
||||
// which sets the directory path to <path> for current logging content output.
|
||||
func (l *Logger) Path(path string) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
@ -44,14 +44,13 @@ func (l *Logger) Path(path string) *Logger {
|
||||
// Param <category> can be hierarchical, eg: module/user.
|
||||
func (l *Logger) Cat(category string) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
path := l.path.Val()
|
||||
if path != "" {
|
||||
logger.SetPath(path + gfile.Separator + category)
|
||||
if logger.path != "" {
|
||||
logger.SetPath(logger.path + gfile.Separator + category)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
@ -60,7 +59,7 @@ func (l *Logger) Cat(category string) *Logger {
|
||||
// which sets file name <pattern> for the current logging content output.
|
||||
func (l *Logger) File(file string) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
@ -73,7 +72,7 @@ func (l *Logger) File(file string) *Logger {
|
||||
// which sets logging level for the current logging content output.
|
||||
func (l *Logger) Level(level int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
@ -82,11 +81,25 @@ func (l *Logger) Level(level int) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Skip is a chaining function,
|
||||
// which sets backtrace skip for the current logging content output.
|
||||
// It also affects the caller file path checks when line number printing enabled.
|
||||
func (l *Logger) Skip(skip int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
logger.SetBacktraceSkip(skip)
|
||||
return logger
|
||||
}
|
||||
|
||||
// Backtrace is a chaining function,
|
||||
// which sets backtrace options for the current logging content output .
|
||||
func (l *Logger) Backtrace(enabled bool, skip...int) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
@ -98,28 +111,63 @@ func (l *Logger) Backtrace(enabled bool, skip...int) *Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// StdPrint is a chaining function,
|
||||
// Stdout is a chaining function,
|
||||
// which enables/disables stdout for the current logging content output.
|
||||
func (l *Logger) StdPrint(enabled bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
logger.SetStdPrint(enabled)
|
||||
return logger
|
||||
// It's enabled in default.
|
||||
func (l *Logger) Stdout(enabled...bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
if len(enabled) > 0 && enabled[0] {
|
||||
logger.stdoutPrint = true
|
||||
} else {
|
||||
logger.stdoutPrint = false
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// See Stdout.
|
||||
// Deprecated.
|
||||
func (l *Logger) StdPrint(enabled...bool) *Logger {
|
||||
return l.Stdout(enabled...)
|
||||
}
|
||||
|
||||
// Header is a chaining function,
|
||||
// which enables/disables log header for the current logging content output.
|
||||
func (l *Logger) Header(enabled bool) *Logger {
|
||||
// It's enabled in default.
|
||||
func (l *Logger) Header(enabled...bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.pr == nil {
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
logger.printHeader.Set(enabled)
|
||||
if len(enabled) > 0 && enabled[0] {
|
||||
logger.SetHeaderPrint(true)
|
||||
} else {
|
||||
logger.SetHeaderPrint(false)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// Line is a chaining function,
|
||||
// which enables/disables printing its caller file path along with its line number.
|
||||
// The param <long> specified whether print the long absolute file path, eg: /a/b/c/d.go:23,
|
||||
// or else short one: d.go:23.
|
||||
func (l *Logger) Line(long...bool) *Logger {
|
||||
logger := (*Logger)(nil)
|
||||
if l.parent == nil {
|
||||
logger = l.Clone()
|
||||
} else {
|
||||
logger = l
|
||||
}
|
||||
if len(long) > 0 && long[0] {
|
||||
logger.flags |= F_FILE_LONG
|
||||
} else {
|
||||
logger.flags |= F_FILE_SHORT
|
||||
}
|
||||
return logger
|
||||
}
|
||||
@ -6,13 +6,9 @@
|
||||
|
||||
package glog
|
||||
|
||||
type Writer struct {
|
||||
logger *Logger
|
||||
}
|
||||
|
||||
// Write implements the io.Writer interface.
|
||||
// It just prints the content with header or level.
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
w.logger.Header(false).Print(string(p))
|
||||
// It just prints the content using Print.
|
||||
func (l *Logger) Write(p []byte) (n int, err error) {
|
||||
l.Header(false).Print(string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
@ -11,7 +11,7 @@ func main() {
|
||||
l := glog.New()
|
||||
path := "/tmp/glog"
|
||||
l.SetPath(path)
|
||||
l.SetStdPrint(false)
|
||||
l.SetStdoutPrint(false)
|
||||
// 使用默认文件名称格式
|
||||
l.Println("标准文件名称格式,使用当前时间时期")
|
||||
// 通过SetFile设置文件名称格式
|
||||
|
||||
15
geg/os/glog/glog_flags.go
Normal file
15
geg/os/glog/glog_flags.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.SetFlags(glog.F_TIME_TIME|glog.F_FILE_SHORT)
|
||||
l.Println("time and short line number")
|
||||
l.SetFlags(glog.F_TIME_MILLI|glog.F_FILE_LONG)
|
||||
l.Println("time with millisecond and long line number")
|
||||
l.SetFlags(glog.F_TIME_STD|glog.F_FILE_LONG)
|
||||
l.Println("standard time format and long line number")
|
||||
}
|
||||
10
geg/os/glog/glog_line.go
Normal file
10
geg/os/glog/glog_line.go
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.Line().Println("this is the short file name with its line number")
|
||||
glog.Line(true).Println("lone file name with line number")
|
||||
}
|
||||
14
geg/os/glog/glog_line2.go
Normal file
14
geg/os/glog/glog_line2.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func PrintLog(content string) {
|
||||
glog.Skip(1).Line().Println("line number with skip:", content)
|
||||
glog.Line().Println("line number without skip:", content)
|
||||
}
|
||||
|
||||
func main() {
|
||||
PrintLog("just test")
|
||||
}
|
||||
12
geg/os/glog/glog_prefix.go
Normal file
12
geg/os/glog/glog_prefix.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glog.New()
|
||||
l.SetPrefix("[API]")
|
||||
l.Println("hello world")
|
||||
l.Error("error occurred")
|
||||
}
|
||||
21
geg/os/glog/glog_stdout.go
Normal file
21
geg/os/glog/glog_stdout.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
wg := sync.WaitGroup{}
|
||||
c := make(chan struct{})
|
||||
wg.Add(3000)
|
||||
for i := 0; i < 3000; i++ {
|
||||
go func() {
|
||||
<-c
|
||||
glog.Println("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
close(c)
|
||||
wg.Wait()
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := glog.GetWriter()
|
||||
w.Write([]byte("hello"))
|
||||
|
||||
glog.Path("/tmp/glog/test").GetWriter().Write([]byte("hello"))
|
||||
}
|
||||
30
geg/os/glog/glog_writer_greylog.go
Normal file
30
geg/os/glog/glog_writer_greylog.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
//import (
|
||||
// "github.com/gogf/gf/g/os/glog"
|
||||
// "github.com/robertkowalski/graylog-golang"
|
||||
//)
|
||||
//
|
||||
//type MyGrayLogWriter struct {
|
||||
// gelf *gelf.Gelf
|
||||
// logger *glog.Logger
|
||||
//}
|
||||
//
|
||||
//func (w *MyGrayLogWriter) Write(p []byte) (n int, err error) {
|
||||
// w.gelf.Send(p)
|
||||
// return w.logger.Write(p)
|
||||
//}
|
||||
//
|
||||
//func main() {
|
||||
// glog.SetWriter(&MyGrayLogWriter{
|
||||
// logger : glog.New(),
|
||||
// gelf : gelf.New(gelf.Config{
|
||||
// GraylogPort : 80,
|
||||
// GraylogHostname : "graylog-host.com",
|
||||
// Connection : "wan",
|
||||
// MaxChunkSizeWan : 42,
|
||||
// MaxChunkSizeLan : 1337,
|
||||
// }),
|
||||
// })
|
||||
// glog.Println("test log")
|
||||
//}
|
||||
28
geg/os/glog/glog_writer_hook.go
Normal file
28
geg/os/glog/glog_writer_hook.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
)
|
||||
|
||||
type MyWriter struct {
|
||||
logger *glog.Logger
|
||||
}
|
||||
|
||||
func (w *MyWriter) Write(p []byte) (n int, err error) {
|
||||
s := string(p)
|
||||
if gregex.IsMatchString(`\[(PANI|FATA)\]`, s) {
|
||||
fmt.Println("SERIOUS ISSUE OCCURRED!! I'd better tell monitor in first time!")
|
||||
ghttp.PostContent("http://monitor.mydomain.com", s)
|
||||
}
|
||||
return w.logger.Write(p)
|
||||
}
|
||||
|
||||
func main() {
|
||||
glog.SetWriter(&MyWriter{
|
||||
logger : glog.New(),
|
||||
})
|
||||
glog.Fatal("FATAL ERROR")
|
||||
}
|
||||
@ -3,12 +3,14 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(gfile.Dir("/"))
|
||||
var mylog = log.New(os.Stdout, "[Api] ", log.LstdFlags|log.Lshortfile)
|
||||
mylog.Println(123)
|
||||
return
|
||||
a := []int{1,2,3}
|
||||
fmt.Println(a[:0])
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.6.13"
|
||||
const VERSION = "v1.6.14"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user