log refactor, add socket handler

This commit is contained in:
siddontang 2014-04-29 16:17:25 +08:00
parent 454a429e10
commit eb13bf9e9b
7 changed files with 417 additions and 176 deletions

179
log/filehandler.go Normal file
View File

@ -0,0 +1,179 @@
package log
import (
"fmt"
"os"
"time"
)
type FileHandler struct {
fd *os.File
}
func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
f, err := os.OpenFile(fileName, flag, 0)
if err != nil {
return nil, err
}
h := new(FileHandler)
h.fd = f
return h, nil
}
func (h *FileHandler) Write(b []byte) (n int, err error) {
return h.fd.Write(b)
}
func (h *FileHandler) Close() error {
return h.fd.Close()
}
type RotatingFileHandler struct {
fd *os.File
fileName string
maxBytes int
backupCount int
}
func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
h := new(RotatingFileHandler)
h.fileName = fileName
h.maxBytes = maxBytes
h.backupCount = backupCount
var err error
h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
return h, nil
}
func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
h.doRollover()
return h.fd.Write(p)
}
func (h *RotatingFileHandler) Close() error {
if h.fd != nil {
return h.fd.Close()
}
return nil
}
func (h *RotatingFileHandler) doRollover() {
f, err := h.fd.Stat()
if err != nil {
return
}
if h.maxBytes <= 0 {
return
} else if f.Size() < int64(h.maxBytes) {
return
}
if h.backupCount > 0 {
h.fd.Close()
for i := h.backupCount - 1; i > 0; i-- {
sfn := fmt.Sprintf("%s.%d", h.fileName, i)
dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
os.Rename(sfn, dfn)
}
dfn := fmt.Sprintf("%s.1", h.fileName)
os.Rename(h.fileName, dfn)
h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
}
}
//refer: http://docs.python.org/2/library/logging.handlers.html
//same like python TimedRotatingFileHandler
type TimeRotatingFileHandler struct {
fd *os.File
baseName string
interval int64
suffix string
rolloverAt int64
}
const (
WhenSecond = iota
WhenMinute
WhenHour
WhenDay
)
func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
h := new(TimeRotatingFileHandler)
h.baseName = baseName
switch when {
case WhenSecond:
h.interval = 1
h.suffix = "2006-01-02_15-04-05"
case WhenMinute:
h.interval = 60
h.suffix = "2006-01-02_15-04"
case WhenHour:
h.interval = 3600
h.suffix = "2006-01-02_15"
case WhenDay:
h.interval = 3600 * 24
h.suffix = "2006-01-02"
default:
return nil, fmt.Errorf("invalid when_rotate: %d", when)
}
h.interval = h.interval * int64(interval)
var err error
h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
fInfo, _ := h.fd.Stat()
h.rolloverAt = fInfo.ModTime().Unix() + h.interval
return h, nil
}
func (h *TimeRotatingFileHandler) doRollover() {
//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
now := time.Now()
if h.rolloverAt <= now.Unix() {
fName := h.baseName + now.Format(h.suffix)
h.fd.Close()
e := os.Rename(h.baseName, fName)
if e != nil {
panic(e)
}
h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
h.rolloverAt = time.Now().Unix() + h.interval
}
}
func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
h.doRollover()
return h.fd.Write(b)
}
func (h *TimeRotatingFileHandler) Close() error {
return h.fd.Close()
}

View File

@ -1,10 +1,7 @@
package log
import (
"fmt"
"io"
"os"
"time"
)
type Handler interface {
@ -46,175 +43,3 @@ func (h *NullHandler) Write(b []byte) (n int, err error) {
func (h *NullHandler) Close() {
}
type FileHandler struct {
fd *os.File
}
func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
f, err := os.OpenFile(fileName, flag, 0)
if err != nil {
return nil, err
}
h := new(FileHandler)
h.fd = f
return h, nil
}
func (h *FileHandler) Write(b []byte) (n int, err error) {
return h.fd.Write(b)
}
func (h *FileHandler) Close() error {
return h.fd.Close()
}
type RotatingFileHandler struct {
fd *os.File
fileName string
maxBytes int
backupCount int
}
func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
h := new(RotatingFileHandler)
h.fileName = fileName
h.maxBytes = maxBytes
h.backupCount = backupCount
var err error
h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
return h, nil
}
func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
h.doRollover()
return h.fd.Write(p)
}
func (h *RotatingFileHandler) Close() error {
if h.fd != nil {
return h.fd.Close()
}
return nil
}
func (h *RotatingFileHandler) doRollover() {
f, err := h.fd.Stat()
if err != nil {
return
}
if h.maxBytes <= 0 {
return
} else if f.Size() < int64(h.maxBytes) {
return
}
if h.backupCount > 0 {
h.fd.Close()
for i := h.backupCount - 1; i > 0; i-- {
sfn := fmt.Sprintf("%s.%d", h.fileName, i)
dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
os.Rename(sfn, dfn)
}
dfn := fmt.Sprintf("%s.1", h.fileName)
os.Rename(h.fileName, dfn)
h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
}
}
//refer: http://docs.python.org/2/library/logging.handlers.html
//same like python TimedRotatingFileHandler
type TimeRotatingFileHandler struct {
fd *os.File
baseName string
interval int64
suffix string
rolloverAt int64
}
const (
WhenSecond = iota
WhenMinute
WhenHour
WhenDay
)
func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
h := new(TimeRotatingFileHandler)
h.baseName = baseName
switch when {
case WhenSecond:
h.interval = 1
h.suffix = "2006-01-02_15-04-05"
case WhenMinute:
h.interval = 60
h.suffix = "2006-01-02_15-04"
case WhenHour:
h.interval = 3600
h.suffix = "2006-01-02_15"
case WhenDay:
h.interval = 3600 * 24
h.suffix = "2006-01-02"
default:
return nil, fmt.Errorf("invalid when_rotate: %d", when)
}
h.interval = h.interval * int64(interval)
var err error
h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
fInfo, _ := h.fd.Stat()
h.rolloverAt = fInfo.ModTime().Unix() + h.interval
return h, nil
}
func (h *TimeRotatingFileHandler) doRollover() {
//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
now := time.Now()
if h.rolloverAt <= now.Unix() {
fName := h.baseName + now.Format(h.suffix)
h.fd.Close()
e := os.Rename(h.baseName, fName)
if e != nil {
panic(e)
}
h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
h.rolloverAt = time.Now().Unix() + h.interval
}
}
func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
h.doRollover()
return h.fd.Write(b)
}
func (h *TimeRotatingFileHandler) Close() error {
return h.fd.Close()
}

View File

@ -125,7 +125,10 @@ func (l *Logger) Output(callDepth int, level int, format string, v ...interface{
s := fmt.Sprintf(format, v...)
buf = append(buf, s...)
buf = append(buf, "\n"...)
if s[len(s)-1] != '\n' {
buf = append(buf, "\n"...)
}
l.msg <- buf
}

21
log/loggingd/main.go Normal file
View File

@ -0,0 +1,21 @@
package main
import (
"flag"
"github.com/siddontang/golib/log"
)
var logFile = flag.String("logfile", "./logd.log", "file to log")
var net = flag.String("net", "tcp", "server listen protocol, like tcp, udp or unix")
var addr = flag.String("addr", "127.0.0.1:11183", "server listen address")
func main() {
flag.Parse()
s, err := log.NewServer(*logFile, *net, *addr)
if err != nil {
panic(err)
}
s.Run()
}

95
log/server.go Normal file
View File

@ -0,0 +1,95 @@
package log
import (
"bufio"
"encoding/binary"
"io"
"net"
"os"
"path"
)
//a log server for handling SocketHandler send log
type Server struct {
closed bool
listener net.Listener
fd *os.File
}
func NewServer(fileName string, protocol string, addr string) (*Server, error) {
s := new(Server)
s.closed = false
var err error
dir := path.Dir(fileName)
os.Mkdir(dir, 0777)
s.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
s.listener, err = net.Listen(protocol, addr)
if err != nil {
return nil, err
}
return s, nil
}
func (s *Server) Close() error {
if s.closed {
return nil
}
s.closed = true
s.fd.Close()
s.listener.Close()
return nil
}
func (s *Server) Run() {
for {
conn, err := s.listener.Accept()
if err != nil {
continue
}
go s.onRead(conn)
}
}
func (s *Server) onRead(c net.Conn) {
br := bufio.NewReaderSize(c, 1024)
var bufLen uint32
for {
if err := binary.Read(br, binary.BigEndian, &bufLen); err != nil {
c.Close()
return
}
buf := make([]byte, bufLen, bufLen+1)
if _, err := io.ReadFull(br, buf); err != nil && err != io.ErrUnexpectedEOF {
c.Close()
return
} else {
if len(buf) == 0 {
continue
}
if buf[len(buf)-1] != '\n' {
buf = append(buf, '\n')
}
s.fd.Write(buf)
}
}
}

56
log/socket_test.go Normal file
View File

@ -0,0 +1,56 @@
package log
import (
"io"
"os"
"testing"
"time"
)
func TestSocket(t *testing.T) {
fileName := "./test_server.log"
os.Remove(fileName)
s, err := NewServer(fileName, "tcp", "127.0.0.1:11183")
if err != nil {
t.Fatal(err)
}
go s.Run()
defer s.Close()
var h *SocketHandler
h, err = NewSocketHandler("tcp", "127.0.0.1:11183")
_, err = h.Write([]byte("hello world"))
if err != nil {
t.Fatal(err)
}
time.Sleep(1 * time.Second)
s.Close()
var f *os.File
f, err = os.Open(fileName)
if err != nil {
t.Fatal(err)
}
defer f.Close()
buf := make([]byte, 64)
var n int
n, err = f.Read(buf)
if err != nil && err != io.EOF {
t.Fatal(err)
}
buf = buf[0:n]
if string(buf) != "hello world\n" {
t.Fatal(string(buf))
}
os.Remove(fileName)
}

62
log/sockethandler.go Normal file
View File

@ -0,0 +1,62 @@
package log
import (
"encoding/binary"
"net"
"time"
)
type SocketHandler struct {
c net.Conn
protocol string
addr string
}
func NewSocketHandler(protocol string, addr string) (*SocketHandler, error) {
s := new(SocketHandler)
s.protocol = protocol
s.addr = addr
return s, nil
}
func (h *SocketHandler) Write(p []byte) (n int, err error) {
if err = h.connect(); err != nil {
return
}
buf := make([]byte, len(p)+4)
binary.BigEndian.PutUint32(buf, uint32(len(p)))
copy(buf[4:], p)
n, err = h.c.Write(buf)
if err != nil {
h.c.Close()
h.c = nil
}
return
}
func (h *SocketHandler) Close() error {
if h.c != nil {
h.c.Close()
}
return nil
}
func (h *SocketHandler) connect() error {
if h.c != nil {
return nil
}
var err error
h.c, err = net.DialTimeout(h.protocol, h.addr, 20*time.Second)
if err != nil {
return err
}
return nil
}