mirror of
https://github.com/datarhei/core.git
synced 2025-12-24 13:07:56 +08:00
Commits (Ingo Oppermann): - Add experimental SRT connection stats and logs - Hide /config/reload endpoint in reade-only mode - Add SRT server - Create v16 in go.mod - Fix data races, tests, lint, and update dependencies - Add trailing slash for routed directories (datarhei/restreamer#340) - Allow relative URLs in content in static routes Co-Authored-By: Ingo Oppermann <57445+ioppermann@users.noreply.github.com>
284 lines
4.3 KiB
Go
284 lines
4.3 KiB
Go
package log
|
|
|
|
import (
|
|
"container/ring"
|
|
"io"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/mattn/go-isatty"
|
|
)
|
|
|
|
type Writer interface {
|
|
Write(e *Event) error
|
|
}
|
|
|
|
type jsonWriter struct {
|
|
writer io.Writer
|
|
level Level
|
|
formatter Formatter
|
|
}
|
|
|
|
func NewJSONWriter(w io.Writer, level Level) Writer {
|
|
writer := &jsonWriter{
|
|
writer: w,
|
|
level: level,
|
|
formatter: NewJSONFormatter(),
|
|
}
|
|
|
|
return NewSyncWriter(writer)
|
|
}
|
|
|
|
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))
|
|
|
|
return err
|
|
}
|
|
|
|
type consoleWriter struct {
|
|
writer io.Writer
|
|
level Level
|
|
formatter Formatter
|
|
}
|
|
|
|
func NewConsoleWriter(w io.Writer, level Level, useColor bool) Writer {
|
|
writer := &consoleWriter{
|
|
writer: w,
|
|
level: level,
|
|
}
|
|
|
|
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 *consoleWriter) Write(e *Event) error {
|
|
if w.level < e.Level || e.Level == Lsilent {
|
|
return nil
|
|
}
|
|
|
|
_, err := w.writer.Write(w.formatter.Bytes(e))
|
|
|
|
return err
|
|
}
|
|
|
|
type topicWriter struct {
|
|
writer Writer
|
|
topics map[string]struct{}
|
|
}
|
|
|
|
func NewTopicWriter(writer Writer, topics []string) Writer {
|
|
w := &topicWriter{
|
|
writer: writer,
|
|
topics: make(map[string]struct{}),
|
|
}
|
|
|
|
for _, topic := range topics {
|
|
topic = strings.ToLower(topic)
|
|
w.topics[topic] = struct{}{}
|
|
}
|
|
|
|
return w
|
|
}
|
|
|
|
func (w *topicWriter) Write(e *Event) error {
|
|
if len(w.topics) > 0 {
|
|
topic := strings.ToLower(e.Component)
|
|
if _, ok := w.topics[topic]; !ok {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
err := w.writer.Write(e)
|
|
|
|
return err
|
|
}
|
|
|
|
type levelRewriter struct {
|
|
writer Writer
|
|
rules []levelRewriteRule
|
|
}
|
|
|
|
type LevelRewriteRule struct {
|
|
Level Level
|
|
Component string
|
|
Match map[string]string
|
|
}
|
|
|
|
type levelRewriteRule struct {
|
|
level Level
|
|
component string
|
|
match map[string]*regexp.Regexp
|
|
}
|
|
|
|
func NewLevelRewriter(writer Writer, rules []LevelRewriteRule) Writer {
|
|
w := &levelRewriter{
|
|
writer: writer,
|
|
}
|
|
|
|
for _, rule := range rules {
|
|
r := levelRewriteRule{
|
|
level: rule.Level,
|
|
component: rule.Component,
|
|
match: make(map[string]*regexp.Regexp),
|
|
}
|
|
|
|
for k, v := range rule.Match {
|
|
re, err := regexp.Compile(v)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
r.match[k] = re
|
|
}
|
|
|
|
w.rules = append(w.rules, r)
|
|
}
|
|
|
|
return w
|
|
}
|
|
|
|
func (w *levelRewriter) Write(e *Event) error {
|
|
rules:
|
|
for _, r := range w.rules {
|
|
if e.Component != r.component {
|
|
continue
|
|
}
|
|
|
|
for k, re := range r.match {
|
|
value, ok := e.Data[k]
|
|
if !ok {
|
|
continue rules
|
|
}
|
|
|
|
switch value := value.(type) {
|
|
case string:
|
|
if !re.MatchString(value) {
|
|
continue rules
|
|
}
|
|
}
|
|
}
|
|
|
|
e.Level = r.level
|
|
}
|
|
|
|
return w.writer.Write(e)
|
|
}
|
|
|
|
type syncWriter struct {
|
|
mu sync.Mutex
|
|
writer Writer
|
|
}
|
|
|
|
func NewSyncWriter(writer Writer) Writer {
|
|
return &syncWriter{
|
|
writer: writer,
|
|
}
|
|
}
|
|
|
|
func (s *syncWriter) Write(e *Event) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
return s.writer.Write(e)
|
|
}
|
|
|
|
type multiWriter struct {
|
|
writer []Writer
|
|
}
|
|
|
|
func NewMultiWriter(writer ...Writer) Writer {
|
|
mw := &multiWriter{}
|
|
|
|
mw.writer = append(mw.writer, writer...)
|
|
|
|
return mw
|
|
}
|
|
|
|
func (m *multiWriter) Write(e *Event) error {
|
|
for _, w := range m.writer {
|
|
if err := w.Write(e); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type BufferWriter interface {
|
|
Writer
|
|
Events() []*Event
|
|
}
|
|
|
|
type bufferWriter struct {
|
|
lines *ring.Ring
|
|
lock sync.RWMutex
|
|
level Level
|
|
}
|
|
|
|
func NewBufferWriter(level Level, lines int) BufferWriter {
|
|
b := &bufferWriter{
|
|
level: level,
|
|
}
|
|
|
|
if lines > 0 {
|
|
b.lines = ring.New(lines)
|
|
}
|
|
|
|
return b
|
|
}
|
|
|
|
func (b *bufferWriter) Write(e *Event) error {
|
|
if b.level < e.Level || e.Level == Lsilent {
|
|
return nil
|
|
}
|
|
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
if b.lines != nil {
|
|
b.lines.Value = e.clone()
|
|
b.lines = b.lines.Next()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *bufferWriter) Events() []*Event {
|
|
var lines = []*Event{}
|
|
|
|
if b.lines == nil {
|
|
return lines
|
|
}
|
|
|
|
b.lock.RLock()
|
|
defer b.lock.RUnlock()
|
|
|
|
b.lines.Do(func(l interface{}) {
|
|
if l == nil {
|
|
return
|
|
}
|
|
|
|
lines = append(lines, l.(*Event).clone())
|
|
})
|
|
|
|
return lines
|
|
}
|