mirror of
https://github.com/42wim/matterbridge.git
synced 2024-12-23 19:52:41 +01:00
143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package mlog
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
|
|
"github.com/mattermost/logr"
|
|
"github.com/wiggin77/merror"
|
|
syslog "github.com/wiggin77/srslog"
|
|
)
|
|
|
|
// Syslog outputs log records to local or remote syslog.
|
|
type Syslog struct {
|
|
logr.Basic
|
|
w *syslog.Writer
|
|
}
|
|
|
|
// SyslogParams provides parameters for dialing a syslog daemon.
|
|
type SyslogParams struct {
|
|
IP string `json:"IP"`
|
|
Port int `json:"Port"`
|
|
Tag string `json:"Tag"`
|
|
TLS bool `json:"TLS"`
|
|
Cert string `json:"Cert"`
|
|
Insecure bool `json:"Insecure"`
|
|
}
|
|
|
|
// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog, with or without TLS.
|
|
func NewSyslogTarget(filter logr.Filter, formatter logr.Formatter, params *SyslogParams, maxQueue int) (*Syslog, error) {
|
|
network := "tcp"
|
|
var config *tls.Config
|
|
|
|
if params.TLS {
|
|
network = "tcp+tls"
|
|
config = &tls.Config{InsecureSkipVerify: params.Insecure}
|
|
if params.Cert != "" {
|
|
pool, err := getCertPool(params.Cert)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.RootCAs = pool
|
|
}
|
|
}
|
|
raddr := fmt.Sprintf("%s:%d", params.IP, params.Port)
|
|
|
|
writer, err := syslog.DialWithTLSConfig(network, raddr, syslog.LOG_INFO, params.Tag, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s := &Syslog{w: writer}
|
|
s.Basic.Start(s, s, filter, formatter, maxQueue)
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// Shutdown stops processing log records after making best effort to flush queue.
|
|
func (s *Syslog) Shutdown(ctx context.Context) error {
|
|
errs := merror.New()
|
|
|
|
err := s.Basic.Shutdown(ctx)
|
|
errs.Append(err)
|
|
|
|
err = s.w.Close()
|
|
errs.Append(err)
|
|
|
|
return errs.ErrorOrNil()
|
|
}
|
|
|
|
// getCertPool returns a x509.CertPool containing the cert(s)
|
|
// from `cert`, which can be a path to a .pem or .crt file,
|
|
// or a base64 encoded cert.
|
|
func getCertPool(cert string) (*x509.CertPool, error) {
|
|
if cert == "" {
|
|
return nil, errors.New("no cert provided")
|
|
}
|
|
|
|
// first treat as a file and try to read.
|
|
serverCert, err := ioutil.ReadFile(cert)
|
|
if err != nil {
|
|
// maybe it's a base64 encoded cert
|
|
serverCert, err = base64.StdEncoding.DecodeString(cert)
|
|
if err != nil {
|
|
return nil, errors.New("cert cannot be read")
|
|
}
|
|
}
|
|
|
|
pool := x509.NewCertPool()
|
|
if ok := pool.AppendCertsFromPEM(serverCert); ok {
|
|
return pool, nil
|
|
}
|
|
return nil, errors.New("cannot parse cert")
|
|
}
|
|
|
|
// Write converts the log record to bytes, via the Formatter,
|
|
// and outputs to syslog.
|
|
func (s *Syslog) Write(rec *logr.LogRec) error {
|
|
_, stacktrace := s.IsLevelEnabled(rec.Level())
|
|
|
|
buf := rec.Logger().Logr().BorrowBuffer()
|
|
defer rec.Logger().Logr().ReleaseBuffer(buf)
|
|
|
|
buf, err := s.Formatter().Format(rec, stacktrace, buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
txt := buf.String()
|
|
|
|
switch rec.Level() {
|
|
case logr.Panic, logr.Fatal:
|
|
err = s.w.Crit(txt)
|
|
case logr.Error:
|
|
err = s.w.Err(txt)
|
|
case logr.Warn:
|
|
err = s.w.Warning(txt)
|
|
case logr.Debug, logr.Trace:
|
|
err = s.w.Debug(txt)
|
|
default:
|
|
// logr.Info plus all custom levels.
|
|
err = s.w.Info(txt)
|
|
}
|
|
|
|
if err != nil {
|
|
reporter := rec.Logger().Logr().ReportError
|
|
reporter(fmt.Errorf("syslog write fail: %w", err))
|
|
// syslog writer will try to reconnect.
|
|
}
|
|
return err
|
|
}
|
|
|
|
// String returns a string representation of this target.
|
|
func (s *Syslog) String() string {
|
|
return "SyslogTarget"
|
|
}
|