18 changed files with 392 additions and 268 deletions
@ -0,0 +1,160 @@
@@ -0,0 +1,160 @@
|
||||
package logger |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io" |
||||
"os" |
||||
"sync" |
||||
"time" |
||||
|
||||
"github.com/aler9/rtsp-simple-server/internal/syslog" |
||||
) |
||||
|
||||
// Level is a log level.
|
||||
type Level int |
||||
|
||||
const ( |
||||
Debug Level = iota |
||||
Info |
||||
Warn |
||||
) |
||||
|
||||
// Log levels.
|
||||
|
||||
// Destination is a log destination.
|
||||
type Destination int |
||||
|
||||
const ( |
||||
// DestinationStdout writes logs to the standard output.
|
||||
DestinationStdout Destination = iota |
||||
|
||||
// DestinationFile writes logs to a file.
|
||||
DestinationFile |
||||
|
||||
// DestinationSyslog writes logs to the system logger.
|
||||
DestinationSyslog |
||||
) |
||||
|
||||
// Logger is a log handler.
|
||||
type Logger struct { |
||||
level Level |
||||
destinations map[Destination]struct{} |
||||
mutex sync.Mutex |
||||
buffer []byte |
||||
|
||||
file *os.File |
||||
syslog io.WriteCloser |
||||
} |
||||
|
||||
// New allocates a log handler.
|
||||
func New(level Level, destinations map[Destination]struct{}, filePath string) (*Logger, error) { |
||||
lh := &Logger{ |
||||
level: level, |
||||
destinations: destinations, |
||||
} |
||||
|
||||
if _, ok := destinations[DestinationFile]; ok { |
||||
var err error |
||||
lh.file, err = os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
lh.Close() |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
if _, ok := destinations[DestinationSyslog]; ok { |
||||
var err error |
||||
lh.syslog, err = syslog.New("rtsp-simple-server") |
||||
if err != nil { |
||||
lh.Close() |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
return lh, nil |
||||
} |
||||
|
||||
// Close closes a log handler.
|
||||
func (lh *Logger) Close() { |
||||
if lh.file != nil { |
||||
lh.file.Close() |
||||
} |
||||
|
||||
if lh.syslog != nil { |
||||
lh.syslog.Close() |
||||
} |
||||
} |
||||
|
||||
// https://golang.org/src/log/log.go#L78
|
||||
func itoa(buf *[]byte, i int, wid int) { |
||||
// Assemble decimal in reverse order.
|
||||
var b [20]byte |
||||
bp := len(b) - 1 |
||||
for i >= 10 || wid > 1 { |
||||
wid-- |
||||
q := i / 10 |
||||
b[bp] = byte('0' + i - q*10) |
||||
bp-- |
||||
i = q |
||||
} |
||||
// i < 10
|
||||
b[bp] = byte('0' + i) |
||||
*buf = append(*buf, b[bp:]...) |
||||
} |
||||
|
||||
func (lh *Logger) Log(level Level, format string, args ...interface{}) { |
||||
if level < lh.level { |
||||
return |
||||
} |
||||
|
||||
lh.mutex.Lock() |
||||
defer lh.mutex.Unlock() |
||||
|
||||
lh.buffer = lh.buffer[:0] |
||||
|
||||
// date
|
||||
now := time.Now() |
||||
year, month, day := now.Date() |
||||
itoa(&lh.buffer, year, 4) |
||||
lh.buffer = append(lh.buffer, '/') |
||||
itoa(&lh.buffer, int(month), 2) |
||||
lh.buffer = append(lh.buffer, '/') |
||||
itoa(&lh.buffer, day, 2) |
||||
lh.buffer = append(lh.buffer, ' ') |
||||
|
||||
// time
|
||||
hour, min, sec := now.Clock() |
||||
itoa(&lh.buffer, hour, 2) |
||||
lh.buffer = append(lh.buffer, ':') |
||||
itoa(&lh.buffer, min, 2) |
||||
lh.buffer = append(lh.buffer, ':') |
||||
itoa(&lh.buffer, sec, 2) |
||||
lh.buffer = append(lh.buffer, ' ') |
||||
|
||||
// level
|
||||
switch level { |
||||
case Debug: |
||||
lh.buffer = append(lh.buffer, "[D] "...) |
||||
|
||||
case Info: |
||||
lh.buffer = append(lh.buffer, "[I] "...) |
||||
|
||||
case Warn: |
||||
lh.buffer = append(lh.buffer, "[W] "...) |
||||
} |
||||
|
||||
// content
|
||||
lh.buffer = append(lh.buffer, fmt.Sprintf(format, args...)...) |
||||
lh.buffer = append(lh.buffer, '\n') |
||||
|
||||
// output
|
||||
if _, ok := lh.destinations[DestinationStdout]; ok { |
||||
print(string(lh.buffer)) |
||||
} |
||||
if _, ok := lh.destinations[DestinationFile]; ok { |
||||
lh.file.Write(lh.buffer) |
||||
} |
||||
if _, ok := lh.destinations[DestinationSyslog]; ok { |
||||
lh.syslog.Write(lh.buffer) |
||||
} |
||||
} |
@ -1,93 +0,0 @@
@@ -1,93 +0,0 @@
|
||||
package loghandler |
||||
|
||||
import ( |
||||
"io" |
||||
"log" |
||||
"os" |
||||
|
||||
"github.com/aler9/rtsp-simple-server/internal/syslog" |
||||
) |
||||
|
||||
// Destination is a log destination.
|
||||
type Destination int |
||||
|
||||
const ( |
||||
// DestinationStdout writes logs to the standard output.
|
||||
DestinationStdout Destination = iota |
||||
|
||||
// DestinationFile writes logs to a file.
|
||||
DestinationFile |
||||
|
||||
// DestinationSyslog writes logs to the system logger.
|
||||
DestinationSyslog |
||||
) |
||||
|
||||
type writeFunc func(p []byte) (int, error) |
||||
|
||||
func (f writeFunc) Write(p []byte) (int, error) { |
||||
return f(p) |
||||
} |
||||
|
||||
// LogHandler is a log handler.
|
||||
type LogHandler struct { |
||||
destinations map[Destination]struct{} |
||||
|
||||
file *os.File |
||||
syslog io.WriteCloser |
||||
} |
||||
|
||||
// New allocates a log handler.
|
||||
func New(destinations map[Destination]struct{}, filePath string) (*LogHandler, error) { |
||||
lh := &LogHandler{ |
||||
destinations: destinations, |
||||
} |
||||
|
||||
if _, ok := destinations[DestinationFile]; ok { |
||||
var err error |
||||
lh.file, err = os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
lh.Close() |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
if _, ok := destinations[DestinationSyslog]; ok { |
||||
var err error |
||||
lh.syslog, err = syslog.New("rtsp-simple-server") |
||||
if err != nil { |
||||
lh.Close() |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
log.SetOutput(writeFunc(lh.write)) |
||||
|
||||
return lh, nil |
||||
} |
||||
|
||||
// Close closes a log handler.
|
||||
func (lh *LogHandler) Close() { |
||||
if lh.file != nil { |
||||
lh.file.Close() |
||||
} |
||||
|
||||
if lh.syslog != nil { |
||||
lh.syslog.Close() |
||||
} |
||||
} |
||||
|
||||
func (lh *LogHandler) write(p []byte) (int, error) { |
||||
if _, ok := lh.destinations[DestinationStdout]; ok { |
||||
print(string(p)) |
||||
} |
||||
|
||||
if _, ok := lh.destinations[DestinationFile]; ok { |
||||
lh.file.Write(p) |
||||
} |
||||
|
||||
if _, ok := lh.destinations[DestinationSyslog]; ok { |
||||
lh.syslog.Write(p) |
||||
} |
||||
|
||||
return len(p), nil |
||||
} |
Loading…
Reference in new issue