mirror of
https://github.com/datarhei/core.git
synced 2025-09-27 20:32:35 +08:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4a12b0293f | ||
![]() |
f472fe150f | ||
![]() |
37e00407cc |
@@ -10,6 +10,7 @@ import (
|
|||||||
gonet "net"
|
gonet "net"
|
||||||
gohttp "net/http"
|
gohttp "net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -147,7 +148,12 @@ func (a *api) Reload() error {
|
|||||||
a.errorChan = make(chan error, 1)
|
a.errorChan = make(chan error, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := log.New("Core").WithOutput(log.NewConsoleWriter(a.log.writer, log.Lwarn, true))
|
logger := log.New("Core").WithOutput(
|
||||||
|
log.NewLevelWriter(
|
||||||
|
log.NewConsoleWriter(a.log.writer, true),
|
||||||
|
log.Lwarn,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
store, err := configstore.NewJSON(a.config.path, func() {
|
store, err := configstore.NewJSON(a.config.path, func() {
|
||||||
a.errorChan <- ErrConfigReload
|
a.errorChan <- ErrConfigReload
|
||||||
@@ -183,31 +189,54 @@ func (a *api) Reload() error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := log.NewBufferWriter(loglevel, cfg.Log.MaxLines)
|
buffer := log.NewBufferWriter(cfg.Log.MaxLines)
|
||||||
|
var writer log.Writer
|
||||||
|
|
||||||
logger = logger.WithOutput(log.NewLevelRewriter(
|
if cfg.Log.Target.Output == "stdout" {
|
||||||
log.NewMultiWriter(
|
writer = log.NewConsoleWriter(
|
||||||
log.NewTopicWriter(
|
os.Stdout,
|
||||||
log.NewConsoleWriter(a.log.writer, loglevel, true),
|
true,
|
||||||
cfg.Log.Topics,
|
)
|
||||||
),
|
} else if cfg.Log.Target.Output == "file" {
|
||||||
buffer,
|
writer = log.NewFileWriter(
|
||||||
),
|
cfg.Log.Target.Path,
|
||||||
[]log.LevelRewriteRule{
|
log.NewJSONFormatter(),
|
||||||
// FFmpeg annoyance, move all warnings about unathorized access to memfs from ffmpeg to debug level
|
)
|
||||||
// ts=2022-04-28T07:24:27Z level=WARN component="HTTP" address=":8080" client="::1" latency_ms=0 method="PUT" path="/memfs/00a10a69-416a-4cd5-9d4f-6d88ed3dd7f5_0917.ts" proto="HTTP/1.1" size_bytes=65 status=401 status_text="Unauthorized" user_agent="Lavf/58.76.100"
|
} else {
|
||||||
{
|
writer = log.NewConsoleWriter(
|
||||||
Level: log.Ldebug,
|
os.Stderr,
|
||||||
Component: "HTTP",
|
true,
|
||||||
Match: map[string]string{
|
)
|
||||||
"client": "^(::1|127.0.0.1)$",
|
}
|
||||||
"method": "^(PUT|POST|DELETE)$",
|
|
||||||
"status_text": "^Unauthorized$",
|
logger = logger.WithOutput(
|
||||||
"user_agent": "^Lavf/",
|
log.NewLevelWriter(
|
||||||
|
log.NewLevelRewriter(
|
||||||
|
log.NewMultiWriter(
|
||||||
|
log.NewTopicWriter(
|
||||||
|
writer,
|
||||||
|
cfg.Log.Topics,
|
||||||
|
),
|
||||||
|
buffer,
|
||||||
|
),
|
||||||
|
[]log.LevelRewriteRule{
|
||||||
|
// FFmpeg annoyance, move all warnings about unathorized access to memfs from ffmpeg to debug level
|
||||||
|
// ts=2022-04-28T07:24:27Z level=WARN component="HTTP" address=":8080" client="::1" latency_ms=0 method="PUT" path="/memfs/00a10a69-416a-4cd5-9d4f-6d88ed3dd7f5_0917.ts" proto="HTTP/1.1" size_bytes=65 status=401 status_text="Unauthorized" user_agent="Lavf/58.76.100"
|
||||||
|
{
|
||||||
|
Level: log.Ldebug,
|
||||||
|
Component: "HTTP",
|
||||||
|
Match: map[string]string{
|
||||||
|
"client": "^(::1|127.0.0.1)$",
|
||||||
|
"method": "^(PUT|POST|DELETE)$",
|
||||||
|
"status_text": "^Unauthorized$",
|
||||||
|
"user_agent": "^Lavf/",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
),
|
||||||
},
|
loglevel,
|
||||||
))
|
),
|
||||||
|
)
|
||||||
|
|
||||||
logfields := log.Fields{
|
logfields := log.Fields{
|
||||||
"application": app.Name,
|
"application": app.Name,
|
||||||
@@ -1297,4 +1326,6 @@ func (a *api) Destroy() {
|
|||||||
a.memfs.DeleteAll()
|
a.memfs.DeleteAll()
|
||||||
a.memfs = nil
|
a.memfs = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.log.logger.core.Close()
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logger := log.New("Migration").WithOutput(log.NewConsoleWriter(os.Stderr, log.Linfo, true)).WithFields(log.Fields{
|
logger := log.New("Migration").WithOutput(
|
||||||
|
log.NewLevelWriter(
|
||||||
|
log.NewConsoleWriter(os.Stderr, true),
|
||||||
|
log.Linfo,
|
||||||
|
),
|
||||||
|
).WithFields(log.Fields{
|
||||||
"from": "ffmpeg4",
|
"from": "ffmpeg4",
|
||||||
"to": "ffmpeg5",
|
"to": "ffmpeg5",
|
||||||
})
|
})
|
||||||
@@ -65,6 +70,27 @@ func doMigration(logger log.Logger, configstore cfgstore.Store) error {
|
|||||||
return fmt.Errorf("the configuration contains errors: %v", messages)
|
return fmt.Errorf("the configuration contains errors: %v", messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var writer log.Writer
|
||||||
|
|
||||||
|
if cfg.Log.Target.Output == "stdout" {
|
||||||
|
writer = log.NewConsoleWriter(
|
||||||
|
os.Stdout,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if cfg.Log.Target.Output == "file" {
|
||||||
|
writer = log.NewFileWriter(
|
||||||
|
cfg.Log.Target.Path,
|
||||||
|
log.NewJSONFormatter(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
writer = log.NewConsoleWriter(
|
||||||
|
os.Stderr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = logger.WithOutput(writer)
|
||||||
|
|
||||||
ff, err := ffmpeg.New(ffmpeg.Config{
|
ff, err := ffmpeg.New(ffmpeg.Config{
|
||||||
Binary: cfg.FFmpeg.Binary,
|
Binary: cfg.FFmpeg.Binary,
|
||||||
})
|
})
|
||||||
|
@@ -13,7 +13,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logger := log.New("Import").WithOutput(log.NewConsoleWriter(os.Stderr, log.Linfo, true)).WithField("version", "v1")
|
logger := log.New("Import").WithOutput(
|
||||||
|
log.NewLevelWriter(
|
||||||
|
log.NewConsoleWriter(os.Stderr, true),
|
||||||
|
log.Linfo,
|
||||||
|
),
|
||||||
|
).WithField("version", "v1")
|
||||||
|
|
||||||
configfile := cfgstore.Location(os.Getenv("CORE_CONFIGFILE"))
|
configfile := cfgstore.Location(os.Getenv("CORE_CONFIGFILE"))
|
||||||
|
|
||||||
@@ -33,8 +38,6 @@ func doImport(logger log.Logger, configstore cfgstore.Store) error {
|
|||||||
logger = log.New("")
|
logger = log.New("")
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info().Log("Database import")
|
|
||||||
|
|
||||||
cfg := configstore.Get()
|
cfg := configstore.Get()
|
||||||
|
|
||||||
// Merging the persisted config with the environment variables
|
// Merging the persisted config with the environment variables
|
||||||
@@ -60,6 +63,27 @@ func doImport(logger log.Logger, configstore cfgstore.Store) error {
|
|||||||
return fmt.Errorf("the configuration contains errors: %v", messages)
|
return fmt.Errorf("the configuration contains errors: %v", messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var writer log.Writer
|
||||||
|
|
||||||
|
if cfg.Log.Target.Output == "stdout" {
|
||||||
|
writer = log.NewConsoleWriter(
|
||||||
|
os.Stdout,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if cfg.Log.Target.Output == "file" {
|
||||||
|
writer = log.NewFileWriter(
|
||||||
|
cfg.Log.Target.Path,
|
||||||
|
log.NewJSONFormatter(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
writer = log.NewConsoleWriter(
|
||||||
|
os.Stderr,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = logger.WithOutput(writer)
|
||||||
|
|
||||||
logger.Info().Log("Checking for database ...")
|
logger.Info().Log("Checking for database ...")
|
||||||
|
|
||||||
// Check if there's a v1.json from the old Restreamer
|
// Check if there's a v1.json from the old Restreamer
|
||||||
|
@@ -141,6 +141,8 @@ func (d *Config) init() {
|
|||||||
d.vars.Register(value.NewString(&d.Log.Level, "info"), "log.level", "CORE_LOG_LEVEL", nil, "Loglevel: silent, error, warn, info, debug", false, false)
|
d.vars.Register(value.NewString(&d.Log.Level, "info"), "log.level", "CORE_LOG_LEVEL", nil, "Loglevel: silent, error, warn, info, debug", false, false)
|
||||||
d.vars.Register(value.NewStringList(&d.Log.Topics, []string{}, ","), "log.topics", "CORE_LOG_TOPICS", nil, "Show only selected log topics", false, false)
|
d.vars.Register(value.NewStringList(&d.Log.Topics, []string{}, ","), "log.topics", "CORE_LOG_TOPICS", nil, "Show only selected log topics", false, false)
|
||||||
d.vars.Register(value.NewInt(&d.Log.MaxLines, 1000), "log.max_lines", "CORE_LOG_MAXLINES", nil, "Number of latest log lines to keep in memory", false, false)
|
d.vars.Register(value.NewInt(&d.Log.MaxLines, 1000), "log.max_lines", "CORE_LOG_MAXLINES", nil, "Number of latest log lines to keep in memory", false, false)
|
||||||
|
d.vars.Register(value.NewString(&d.Log.Target.Output, "stderr"), "log.target.output", "CORE_LOG_TARGET_OUTPUT", nil, "Where to write the logs to: stdout, stderr, file", false, false)
|
||||||
|
d.vars.Register(value.NewString(&d.Log.Target.Path, ""), "log.target.path", "CORE_LOG_TARGET_PATH", nil, "Path to log file if output is 'file'", false, false)
|
||||||
|
|
||||||
// DB
|
// DB
|
||||||
d.vars.Register(value.NewMustDir(&d.DB.Dir, "./config"), "db.dir", "CORE_DB_DIR", nil, "Directory for holding the operational data", false, false)
|
d.vars.Register(value.NewMustDir(&d.DB.Dir, "./config"), "db.dir", "CORE_DB_DIR", nil, "Directory for holding the operational data", false, false)
|
||||||
|
@@ -22,6 +22,10 @@ type Data struct {
|
|||||||
Level string `json:"level" enums:"debug,info,warn,error,silent" jsonschema:"enum=debug,enum=info,enum=warn,enum=error,enum=silent"`
|
Level string `json:"level" enums:"debug,info,warn,error,silent" jsonschema:"enum=debug,enum=info,enum=warn,enum=error,enum=silent"`
|
||||||
Topics []string `json:"topics"`
|
Topics []string `json:"topics"`
|
||||||
MaxLines int `json:"max_lines"`
|
MaxLines int `json:"max_lines"`
|
||||||
|
Target struct {
|
||||||
|
Output string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
} `json:"target"` // discard, stderr, stdout, file:/path/to/file.log
|
||||||
} `json:"log"`
|
} `json:"log"`
|
||||||
DB struct {
|
DB struct {
|
||||||
Dir string `json:"dir"`
|
Dir string `json:"dir"`
|
||||||
@@ -182,7 +186,6 @@ func MergeV2toV3(data *Data, d *v2.Data) (*Data, error) {
|
|||||||
data.Address = d.Address
|
data.Address = d.Address
|
||||||
data.CheckForUpdates = d.CheckForUpdates
|
data.CheckForUpdates = d.CheckForUpdates
|
||||||
|
|
||||||
data.Log = d.Log
|
|
||||||
data.DB = d.DB
|
data.DB = d.DB
|
||||||
data.Host = d.Host
|
data.Host = d.Host
|
||||||
data.API = d.API
|
data.API = d.API
|
||||||
@@ -195,8 +198,6 @@ func MergeV2toV3(data *Data, d *v2.Data) (*Data, error) {
|
|||||||
data.Service = d.Service
|
data.Service = d.Service
|
||||||
data.Router = d.Router
|
data.Router = d.Router
|
||||||
|
|
||||||
data.Log.Topics = copy.Slice(d.Log.Topics)
|
|
||||||
|
|
||||||
data.Host.Name = copy.Slice(d.Host.Name)
|
data.Host.Name = copy.Slice(d.Host.Name)
|
||||||
|
|
||||||
data.API.Access.HTTP.Allow = copy.Slice(d.API.Access.HTTP.Allow)
|
data.API.Access.HTTP.Allow = copy.Slice(d.API.Access.HTTP.Allow)
|
||||||
@@ -228,6 +229,12 @@ func MergeV2toV3(data *Data, d *v2.Data) (*Data, error) {
|
|||||||
data.Storage.Memory = d.Storage.Memory
|
data.Storage.Memory = d.Storage.Memory
|
||||||
|
|
||||||
// Actual changes
|
// Actual changes
|
||||||
|
data.Log.Level = d.Log.Level
|
||||||
|
data.Log.Topics = copy.Slice(d.Log.Topics)
|
||||||
|
data.Log.MaxLines = d.Log.MaxLines
|
||||||
|
data.Log.Target.Output = "stderr"
|
||||||
|
data.Log.Target.Path = ""
|
||||||
|
|
||||||
data.Debug.Profiling = d.Debug.Profiling
|
data.Debug.Profiling = d.Debug.Profiling
|
||||||
data.Debug.ForceGC = d.Debug.ForceGC
|
data.Debug.ForceGC = d.Debug.ForceGC
|
||||||
data.Debug.MemoryLimit = 0
|
data.Debug.MemoryLimit = 0
|
||||||
@@ -263,7 +270,6 @@ func DowngradeV3toV2(d *Data) (*v2.Data, error) {
|
|||||||
data.Address = d.Address
|
data.Address = d.Address
|
||||||
data.CheckForUpdates = d.CheckForUpdates
|
data.CheckForUpdates = d.CheckForUpdates
|
||||||
|
|
||||||
data.Log = d.Log
|
|
||||||
data.DB = d.DB
|
data.DB = d.DB
|
||||||
data.Host = d.Host
|
data.Host = d.Host
|
||||||
data.API = d.API
|
data.API = d.API
|
||||||
@@ -276,8 +282,6 @@ func DowngradeV3toV2(d *Data) (*v2.Data, error) {
|
|||||||
data.Service = d.Service
|
data.Service = d.Service
|
||||||
data.Router = d.Router
|
data.Router = d.Router
|
||||||
|
|
||||||
data.Log.Topics = copy.Slice(d.Log.Topics)
|
|
||||||
|
|
||||||
data.Host.Name = copy.Slice(d.Host.Name)
|
data.Host.Name = copy.Slice(d.Host.Name)
|
||||||
|
|
||||||
data.API.Access.HTTP.Allow = copy.Slice(d.API.Access.HTTP.Allow)
|
data.API.Access.HTTP.Allow = copy.Slice(d.API.Access.HTTP.Allow)
|
||||||
@@ -302,6 +306,10 @@ func DowngradeV3toV2(d *Data) (*v2.Data, error) {
|
|||||||
data.Router.Routes = copy.StringMap(d.Router.Routes)
|
data.Router.Routes = copy.StringMap(d.Router.Routes)
|
||||||
|
|
||||||
// Actual changes
|
// Actual changes
|
||||||
|
data.Log.Level = d.Log.Level
|
||||||
|
data.Log.Topics = copy.Slice(d.Log.Topics)
|
||||||
|
data.Log.MaxLines = d.Log.MaxLines
|
||||||
|
|
||||||
data.Debug.Profiling = d.Debug.Profiling
|
data.Debug.Profiling = d.Debug.Profiling
|
||||||
data.Debug.ForceGC = d.Debug.ForceGC
|
data.Debug.ForceGC = d.Debug.ForceGC
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
func (r *queryResolver) Log(ctx context.Context) ([]string, error) {
|
func (r *queryResolver) Log(ctx context.Context) ([]string, error) {
|
||||||
if r.LogBuffer == nil {
|
if r.LogBuffer == nil {
|
||||||
r.LogBuffer = log.NewBufferWriter(log.Lsilent, 1)
|
r.LogBuffer = log.NewBufferWriter(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
events := r.LogBuffer.Events()
|
events := r.LogBuffer.Events()
|
||||||
|
@@ -22,7 +22,7 @@ func NewLog(buffer log.BufferWriter) *LogHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if l.buffer == nil {
|
if l.buffer == nil {
|
||||||
l.buffer = log.NewBufferWriter(log.Lsilent, 1)
|
l.buffer = log.NewBufferWriter(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return l
|
return l
|
||||||
|
50
log/log.go
50
log/log.go
@@ -14,28 +14,29 @@ import (
|
|||||||
type Level uint
|
type Level uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Lsilent Level = 0
|
Lsilent Level = 0b0000
|
||||||
Lerror Level = 1
|
Lerror Level = 0b0001
|
||||||
Lwarn Level = 2
|
Lwarn Level = 0b0010
|
||||||
Linfo Level = 3
|
Linfo Level = 0b0100
|
||||||
Ldebug Level = 4
|
Ldebug Level = 0b1000
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns a string representing the log level.
|
// String returns a string representing the log level.
|
||||||
func (level Level) String() string {
|
func (level Level) String() string {
|
||||||
names := []string{
|
switch level {
|
||||||
"SILENT",
|
case Lsilent:
|
||||||
"ERROR",
|
return "SILENT"
|
||||||
"WARN",
|
case Lerror:
|
||||||
"INFO",
|
return "ERROR"
|
||||||
"DEBUG",
|
case Lwarn:
|
||||||
}
|
return "WARN"
|
||||||
|
case Linfo:
|
||||||
if level > Ldebug {
|
return "INFO"
|
||||||
|
case Ldebug:
|
||||||
|
return "DEBUG"
|
||||||
|
default:
|
||||||
return `¯\_(ツ)_/¯`
|
return `¯\_(ツ)_/¯`
|
||||||
}
|
}
|
||||||
|
|
||||||
return names[level]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (level *Level) MarshalJSON() ([]byte, error) {
|
func (level *Level) MarshalJSON() ([]byte, error) {
|
||||||
@@ -97,6 +98,9 @@ type Logger interface {
|
|||||||
// Write implements the io.Writer interface such that it can be used in e.g. the
|
// Write implements the io.Writer interface such that it can be used in e.g. the
|
||||||
// the log/Logger facility. Messages will be printed with debug level.
|
// the log/Logger facility. Messages will be printed with debug level.
|
||||||
Write(p []byte) (int, error)
|
Write(p []byte) (int, error)
|
||||||
|
|
||||||
|
// Close closes the underlying writer.
|
||||||
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// logger is an implementation of the Logger interface.
|
// logger is an implementation of the Logger interface.
|
||||||
@@ -184,6 +188,10 @@ func (l *logger) Write(p []byte) (int, error) {
|
|||||||
return newEvent(l).Write(p)
|
return newEvent(l).Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *logger) Close() {
|
||||||
|
l.output.Close()
|
||||||
|
}
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
logger *logger
|
logger *logger
|
||||||
|
|
||||||
@@ -352,12 +360,6 @@ func (l *Event) Write(p []byte) (int, error) {
|
|||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Eventx struct {
|
func (l *Event) Close() {
|
||||||
Time time.Time `json:"ts"`
|
l.logger.Close()
|
||||||
Level Level `json:"level"`
|
|
||||||
Component string `json:"component"`
|
|
||||||
Reference string `json:"ref"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Caller string `json:"caller"`
|
|
||||||
Detail interface{} `json:"detail"`
|
|
||||||
}
|
}
|
||||||
|
@@ -5,25 +5,25 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoglevelNames(t *testing.T) {
|
func TestLoglevelNames(t *testing.T) {
|
||||||
assert.Equal(t, "DEBUG", Ldebug.String())
|
require.Equal(t, "DEBUG", Ldebug.String())
|
||||||
assert.Equal(t, "ERROR", Lerror.String())
|
require.Equal(t, "ERROR", Lerror.String())
|
||||||
assert.Equal(t, "WARN", Lwarn.String())
|
require.Equal(t, "WARN", Lwarn.String())
|
||||||
assert.Equal(t, "INFO", Linfo.String())
|
require.Equal(t, "INFO", Linfo.String())
|
||||||
assert.Equal(t, `SILENT`, Lsilent.String())
|
require.Equal(t, `SILENT`, Lsilent.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogColorToNotTTY(t *testing.T) {
|
func TestLogColorToNotTTY(t *testing.T) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
w := NewConsoleWriter(writer, Linfo, true).(*syncWriter)
|
w := NewLevelWriter(NewConsoleWriter(writer, true), Linfo).(*levelWriter).writer.(*syncWriter)
|
||||||
formatter := w.writer.(*consoleWriter).formatter.(*consoleFormatter)
|
formatter := w.writer.(*consoleWriter).formatter.(*consoleFormatter)
|
||||||
|
|
||||||
assert.NotEqual(t, true, formatter.color, "Color should not be used on a buffer logger")
|
require.NotEqual(t, true, formatter.color, "Color should not be used on a buffer logger")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogContext(t *testing.T) {
|
func TestLogContext(t *testing.T) {
|
||||||
@@ -31,7 +31,7 @@ func TestLogContext(t *testing.T) {
|
|||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("component").WithOutput(NewConsoleWriter(writer, Ldebug, false))
|
logger := New("component").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Ldebug))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
@@ -53,19 +53,19 @@ func TestLogContext(t *testing.T) {
|
|||||||
lenWithoutCtx := buffer.Len()
|
lenWithoutCtx := buffer.Len()
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
assert.Greater(t, lenWithCtx, lenWithoutCtx, "Log line length without context is not shorter than with context")
|
require.Greater(t, lenWithCtx, lenWithoutCtx, "Log line length without context is not shorter than with context")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogClone(t *testing.T) {
|
func TestLogClone(t *testing.T) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Linfo, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Linfo))
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
|
|
||||||
assert.Contains(t, buffer.String(), `component="test"`)
|
require.Contains(t, buffer.String(), `component="test"`)
|
||||||
|
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
@@ -74,33 +74,33 @@ func TestLogClone(t *testing.T) {
|
|||||||
logger2.Info().Log("info")
|
logger2.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
|
|
||||||
assert.Contains(t, buffer.String(), `component="tset"`)
|
require.Contains(t, buffer.String(), `component="tset"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogSilent(t *testing.T) {
|
func TestLogSilent(t *testing.T) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Lsilent, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Lsilent))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Warn().Log("warn")
|
logger.Warn().Log("warn")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Error().Log("error")
|
logger.Error().Log("error")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,26 +108,26 @@ func TestLogDebug(t *testing.T) {
|
|||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Ldebug, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Ldebug))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Warn().Log("warn")
|
logger.Warn().Log("warn")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Error().Log("error")
|
logger.Error().Log("error")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,26 +135,26 @@ func TestLogInfo(t *testing.T) {
|
|||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Linfo, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Linfo))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Warn().Log("warn")
|
logger.Warn().Log("warn")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Error().Log("error")
|
logger.Error().Log("error")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,26 +162,26 @@ func TestLogWarn(t *testing.T) {
|
|||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Lwarn, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Lwarn))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Warn().Log("warn")
|
logger.Warn().Log("warn")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Error().Log("error")
|
logger.Error().Log("error")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,25 +189,25 @@ func TestLogError(t *testing.T) {
|
|||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
writer := bufio.NewWriter(&buffer)
|
writer := bufio.NewWriter(&buffer)
|
||||||
|
|
||||||
logger := New("test").WithOutput(NewConsoleWriter(writer, Lerror, false))
|
logger := New("test").WithOutput(NewLevelWriter(NewConsoleWriter(writer, false), Lerror))
|
||||||
|
|
||||||
logger.Debug().Log("debug")
|
logger.Debug().Log("debug")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Info().Log("info")
|
logger.Info().Log("info")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Warn().Log("warn")
|
logger.Warn().Log("warn")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
require.Equal(t, 0, buffer.Len(), "Buffer should be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
|
|
||||||
logger.Error().Log("error")
|
logger.Error().Log("error")
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
assert.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
require.NotEqual(t, 0, buffer.Len(), "Buffer should not be empty")
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
}
|
}
|
||||||
|
43
log/output.go
Normal file
43
log/output.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
|
)
|
||||||
|
|
||||||
|
type consoleOutput struct {
|
||||||
|
writer io.Writer
|
||||||
|
formatter Formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConsoleOutput(w io.Writer, useColor bool) Writer {
|
||||||
|
writer := &consoleOutput{
|
||||||
|
writer: w,
|
||||||
|
}
|
||||||
|
|
||||||
|
color := useColor
|
||||||
|
|
||||||
|
if color {
|
||||||
|
if w, ok := w.(*os.File); ok {
|
||||||
|
if !isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()) {
|
||||||
|
color = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
color = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.formatter = NewConsoleFormatter(color)
|
||||||
|
|
||||||
|
return NewSyncWriter(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *consoleOutput) Write(e *Event) error {
|
||||||
|
_, err := w.writer.Write(w.formatter.Bytes(e))
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *consoleOutput) Close() {}
|
148
log/writer.go
148
log/writer.go
@@ -13,18 +13,50 @@ import (
|
|||||||
|
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(e *Event) error
|
Write(e *Event) error
|
||||||
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type discardWriter struct{}
|
||||||
|
|
||||||
|
func NewDiscardWriter() Writer {
|
||||||
|
return &discardWriter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *discardWriter) Write(e *Event) error { return nil }
|
||||||
|
func (w *discardWriter) Close() {}
|
||||||
|
|
||||||
|
type levelWriter struct {
|
||||||
|
writer Writer
|
||||||
|
level Level
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLevelWriter(w Writer, level Level) Writer {
|
||||||
|
return &levelWriter{
|
||||||
|
writer: w,
|
||||||
|
level: level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *levelWriter) Write(e *Event) error {
|
||||||
|
if w.level < e.Level || e.Level == Lsilent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.writer.Write(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *levelWriter) Close() {
|
||||||
|
w.writer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonWriter struct {
|
type jsonWriter struct {
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
level Level
|
|
||||||
formatter Formatter
|
formatter Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJSONWriter(w io.Writer, level Level) Writer {
|
func NewJSONWriter(w io.Writer) Writer {
|
||||||
writer := &jsonWriter{
|
writer := &jsonWriter{
|
||||||
writer: w,
|
writer: w,
|
||||||
level: level,
|
|
||||||
formatter: NewJSONFormatter(),
|
formatter: NewJSONFormatter(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,25 +64,21 @@ func NewJSONWriter(w io.Writer, level Level) Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *jsonWriter) Write(e *Event) error {
|
func (w *jsonWriter) Write(e *Event) error {
|
||||||
if w.level < e.Level || e.Level == Lsilent {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := w.writer.Write(w.formatter.Bytes(e))
|
_, err := w.writer.Write(w.formatter.Bytes(e))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *jsonWriter) Close() {}
|
||||||
|
|
||||||
type consoleWriter struct {
|
type consoleWriter struct {
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
level Level
|
|
||||||
formatter Formatter
|
formatter Formatter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsoleWriter(w io.Writer, level Level, useColor bool) Writer {
|
func NewConsoleWriter(w io.Writer, useColor bool) Writer {
|
||||||
writer := &consoleWriter{
|
writer := &consoleWriter{
|
||||||
writer: w,
|
writer: w,
|
||||||
level: level,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
color := useColor
|
color := useColor
|
||||||
@@ -71,15 +99,13 @@ func NewConsoleWriter(w io.Writer, level Level, useColor bool) Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *consoleWriter) Write(e *Event) error {
|
func (w *consoleWriter) Write(e *Event) error {
|
||||||
if w.level < e.Level || e.Level == Lsilent {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := w.writer.Write(w.formatter.Bytes(e))
|
_, err := w.writer.Write(w.formatter.Bytes(e))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *consoleWriter) Close() {}
|
||||||
|
|
||||||
type topicWriter struct {
|
type topicWriter struct {
|
||||||
writer Writer
|
writer Writer
|
||||||
topics map[string]struct{}
|
topics map[string]struct{}
|
||||||
@@ -112,6 +138,10 @@ func (w *topicWriter) Write(e *Event) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *topicWriter) Close() {
|
||||||
|
w.writer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
type levelRewriter struct {
|
type levelRewriter struct {
|
||||||
writer Writer
|
writer Writer
|
||||||
rules []levelRewriteRule
|
rules []levelRewriteRule
|
||||||
@@ -182,6 +212,10 @@ rules:
|
|||||||
return w.writer.Write(e)
|
return w.writer.Write(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *levelRewriter) Close() {
|
||||||
|
w.writer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
type syncWriter struct {
|
type syncWriter struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
writer Writer
|
writer Writer
|
||||||
@@ -193,11 +227,15 @@ func NewSyncWriter(writer Writer) Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *syncWriter) Write(e *Event) error {
|
func (w *syncWriter) Write(e *Event) error {
|
||||||
s.mu.Lock()
|
w.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
return s.writer.Write(e)
|
return w.writer.Write(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *syncWriter) Close() {
|
||||||
|
w.writer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type multiWriter struct {
|
type multiWriter struct {
|
||||||
@@ -212,8 +250,8 @@ func NewMultiWriter(writer ...Writer) Writer {
|
|||||||
return mw
|
return mw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multiWriter) Write(e *Event) error {
|
func (w *multiWriter) Write(e *Event) error {
|
||||||
for _, w := range m.writer {
|
for _, w := range w.writer {
|
||||||
if err := w.Write(e); err != nil {
|
if err := w.Write(e); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -222,6 +260,12 @@ func (m *multiWriter) Write(e *Event) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *multiWriter) Close() {
|
||||||
|
for _, w := range w.writer {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type BufferWriter interface {
|
type BufferWriter interface {
|
||||||
Writer
|
Writer
|
||||||
Events() []*Event
|
Events() []*Event
|
||||||
@@ -230,13 +274,10 @@ type BufferWriter interface {
|
|||||||
type bufferWriter struct {
|
type bufferWriter struct {
|
||||||
lines *ring.Ring
|
lines *ring.Ring
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
level Level
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBufferWriter(level Level, lines int) BufferWriter {
|
func NewBufferWriter(lines int) BufferWriter {
|
||||||
b := &bufferWriter{
|
b := &bufferWriter{}
|
||||||
level: level,
|
|
||||||
}
|
|
||||||
|
|
||||||
if lines > 0 {
|
if lines > 0 {
|
||||||
b.lines = ring.New(lines)
|
b.lines = ring.New(lines)
|
||||||
@@ -245,33 +286,31 @@ func NewBufferWriter(level Level, lines int) BufferWriter {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bufferWriter) Write(e *Event) error {
|
func (w *bufferWriter) Write(e *Event) error {
|
||||||
if b.level < e.Level || e.Level == Lsilent {
|
w.lock.Lock()
|
||||||
return nil
|
defer w.lock.Unlock()
|
||||||
}
|
|
||||||
|
|
||||||
b.lock.Lock()
|
if w.lines != nil {
|
||||||
defer b.lock.Unlock()
|
w.lines.Value = e.clone()
|
||||||
|
w.lines = w.lines.Next()
|
||||||
if b.lines != nil {
|
|
||||||
b.lines.Value = e.clone()
|
|
||||||
b.lines = b.lines.Next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bufferWriter) Events() []*Event {
|
func (w *bufferWriter) Close() {}
|
||||||
|
|
||||||
|
func (w *bufferWriter) Events() []*Event {
|
||||||
var lines = []*Event{}
|
var lines = []*Event{}
|
||||||
|
|
||||||
if b.lines == nil {
|
if w.lines == nil {
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
b.lock.RLock()
|
w.lock.RLock()
|
||||||
defer b.lock.RUnlock()
|
defer w.lock.RUnlock()
|
||||||
|
|
||||||
b.lines.Do(func(l interface{}) {
|
w.lines.Do(func(l interface{}) {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -281,3 +320,32 @@ func (b *bufferWriter) Events() []*Event {
|
|||||||
|
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fileWriter struct {
|
||||||
|
writer *os.File
|
||||||
|
formatter Formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileWriter(path string, formatter Formatter) Writer {
|
||||||
|
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR|os.O_SYNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return NewDiscardWriter()
|
||||||
|
}
|
||||||
|
|
||||||
|
writer := &fileWriter{
|
||||||
|
writer: file,
|
||||||
|
formatter: formatter,
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewSyncWriter(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *fileWriter) Write(e *Event) error {
|
||||||
|
_, err := w.writer.Write(append(w.formatter.Bytes(e), '\n'))
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *fileWriter) Close() {
|
||||||
|
w.writer.Close()
|
||||||
|
}
|
||||||
|
12
main.go
12
main.go
@@ -12,7 +12,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logger := log.New("Core").WithOutput(log.NewConsoleWriter(os.Stderr, log.Lwarn, true))
|
logger := log.New("Core").WithOutput(
|
||||||
|
log.NewLevelWriter(
|
||||||
|
log.NewConsoleWriter(
|
||||||
|
os.Stderr,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
log.Lwarn,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
configfile := store.Location(os.Getenv("CORE_CONFIGFILE"))
|
configfile := store.Location(os.Getenv("CORE_CONFIGFILE"))
|
||||||
|
|
||||||
@@ -54,6 +62,8 @@ func main() {
|
|||||||
signal.Notify(quit, os.Interrupt)
|
signal.Notify(quit, os.Interrupt)
|
||||||
<-quit
|
<-quit
|
||||||
|
|
||||||
|
logger.Close()
|
||||||
|
|
||||||
// Stop the app
|
// Stop the app
|
||||||
app.Destroy()
|
app.Destroy()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user