134 строки
3.2 KiB
Go
134 строки
3.2 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package audit
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
|
|
"github.com/wiggin77/logr"
|
|
"github.com/wiggin77/merror"
|
|
syslog "github.com/wiggin77/srslog"
|
|
)
|
|
|
|
// Syslog outputs log records to local or remote syslog.
|
|
type SyslogTLS struct {
|
|
logr.Basic
|
|
w *syslog.Writer
|
|
}
|
|
|
|
// SyslogParams provides parameters for dialing a syslogTLS daemon.
|
|
type SyslogParams struct {
|
|
Raddr string
|
|
Cert string
|
|
Tag string
|
|
Insecure bool
|
|
}
|
|
|
|
// NewSyslogTLSTarget creates a target capable of outputting log records to remote or local syslog via TLS.
|
|
func NewSyslogTLSTarget(filter logr.Filter, formatter logr.Formatter, params *SyslogParams, maxQueue int) (*SyslogTLS, error) {
|
|
config := tls.Config{InsecureSkipVerify: params.Insecure}
|
|
if params.Cert != "" {
|
|
pool, err := getCertPool(params.Cert)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.RootCAs = pool
|
|
}
|
|
|
|
writer, err := syslog.DialWithTLSConfig("tcp+tls", params.Raddr, syslog.LOG_INFO, params.Tag, &config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s := &SyslogTLS{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 *SyslogTLS) 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 via TLS.
|
|
func (s *SyslogTLS) 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))
|
|
// syslogTLS writer will try to reconnect.
|
|
}
|
|
return err
|
|
}
|
|
|
|
// String returns a string representation of this target.
|
|
func (s *SyslogTLS) String() string {
|
|
return "SyslogTLSTarget"
|
|
}
|