Merge pull request #5739 from hashicorp/r-rm-logmon-syslog-deadcode

logmon: remove syslog server deadcode
This commit is contained in:
Mahmood Ali
2019-05-21 11:46:48 -04:00
committed by GitHub
17 changed files with 0 additions and 1357 deletions

View File

@@ -1,159 +0,0 @@
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package logging
import (
"fmt"
"strconv"
syslog "github.com/RackSec/srslog"
hclog "github.com/hashicorp/go-hclog"
)
// Errors related to parsing priority
var (
ErrPriorityNoStart = fmt.Errorf("No start char found for priority")
ErrPriorityEmpty = fmt.Errorf("Priority field empty")
ErrPriorityNoEnd = fmt.Errorf("No end char found for priority")
ErrPriorityTooShort = fmt.Errorf("Priority field too short")
ErrPriorityTooLong = fmt.Errorf("Priority field too long")
ErrPriorityNonDigit = fmt.Errorf("Non digit found in priority")
)
// Priority header and ending characters
const (
PRI_PART_START = '<'
PRI_PART_END = '>'
)
// SyslogMessage represents a log line received
type SyslogMessage struct {
Message []byte
Severity syslog.Priority
}
// Priority holds all the priority bits in a syslog log line
type Priority struct {
Pri int
Facility syslog.Priority
Severity syslog.Priority
}
// DockerLogParser parses a line of log message that the docker daemon ships
type DockerLogParser struct {
logger hclog.Logger
}
// NewDockerLogParser creates a new DockerLogParser
func NewDockerLogParser(logger hclog.Logger) *DockerLogParser {
return &DockerLogParser{logger: logger}
}
// Parse parses a syslog log line
func (d *DockerLogParser) Parse(line []byte) *SyslogMessage {
pri, _, _ := d.parsePriority(line)
msgIdx := d.logContentIndex(line)
// Create a copy of the line so that subsequent Scans do not override the
// message
lineCopy := make([]byte, len(line[msgIdx:]))
copy(lineCopy, line[msgIdx:])
return &SyslogMessage{
Severity: pri.Severity,
Message: lineCopy,
}
}
// logContentIndex finds out the index of the start index of the content in a
// syslog line
func (d *DockerLogParser) logContentIndex(line []byte) int {
cursor := 0
numSpace := 0
numColons := 0
// first look for at least 2 colons. This matches into the date that has no more spaces in it
// DefaultFormatter log line look: '<30>2016-07-06T15:13:11Z00:00 hostname docker/9648c64f5037[16200]'
// UnixFormatter log line look: '<30>Jul 6 15:13:11 docker/9648c64f5037[16200]'
for i := 0; i < len(line); i++ {
if line[i] == ':' {
numColons += 1
if numColons == 2 {
cursor = i
break
}
}
}
// then look for the next space
for i := cursor; i < len(line); i++ {
if line[i] == ' ' {
numSpace += 1
if numSpace == 1 {
cursor = i
break
}
}
}
// then the colon is what separates it, followed by a space
for i := cursor; i < len(line); i++ {
if line[i] == ':' && i+1 < len(line) && line[i+1] == ' ' {
cursor = i + 1
break
}
}
// return the cursor to the next character
return cursor + 1
}
// parsePriority parses the priority in a syslog message
func (d *DockerLogParser) parsePriority(line []byte) (Priority, int, error) {
cursor := 0
pri := d.newPriority(0)
if len(line) <= 0 {
return pri, cursor, ErrPriorityEmpty
}
if line[cursor] != PRI_PART_START {
return pri, cursor, ErrPriorityNoStart
}
i := 1
priDigit := 0
for i < len(line) {
if i >= 5 {
return pri, cursor, ErrPriorityTooLong
}
c := line[i]
if c == PRI_PART_END {
if i == 1 {
return pri, cursor, ErrPriorityTooShort
}
cursor = i + 1
return d.newPriority(priDigit), cursor, nil
}
if d.isDigit(c) {
v, e := strconv.Atoi(string(c))
if e != nil {
return pri, cursor, e
}
priDigit = (priDigit * 10) + v
} else {
return pri, cursor, ErrPriorityNonDigit
}
i++
}
return pri, cursor, ErrPriorityNoEnd
}
// isDigit checks if a byte is a numeric char
func (d *DockerLogParser) isDigit(c byte) bool {
return c >= '0' && c <= '9'
}
// newPriority creates a new default priority
func (d *DockerLogParser) newPriority(p int) Priority {
// The Priority value is calculated by first multiplying the Facility
// number by 8 and then adding the numerical value of the Severity.
return Priority{
Pri: p,
Facility: syslog.Priority(p / 8),
Severity: syslog.Priority(p % 8),
}
}

View File

@@ -1,49 +0,0 @@
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package logging
import (
"bytes"
"testing"
syslog "github.com/RackSec/srslog"
"github.com/hashicorp/nomad/helper/testlog"
)
func TestLogParser_Priority(t *testing.T) {
t.Parallel()
line := []byte("<30>2016-02-10T10:16:43-08:00 d-thinkpad docker/e2a1e3ebd3a3[22950]: 1:C 10 Feb 18:16:43.391 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf")
d := NewDockerLogParser(testlog.HCLogger(t))
p, _, err := d.parsePriority(line)
if err != nil {
t.Fatalf("got an err: %v", err)
}
if p.Severity != syslog.LOG_INFO {
t.Fatalf("expected severity: %v, got: %v", syslog.LOG_INFO, p.Severity)
}
idx := d.logContentIndex(line)
expected := bytes.Index(line, []byte("1:C 10 Feb 18:16:43.391"))
if idx != expected {
t.Fatalf("expected idx: %v, got: %v", expected, idx)
}
}
func TestLogParser_Priority_UnixFormatter(t *testing.T) {
t.Parallel()
line := []byte("<30>Feb 6, 10:16:43 docker/e2a1e3ebd3a3[22950]: 1:C 10 Feb 18:16:43.391 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf")
d := NewDockerLogParser(testlog.HCLogger(t))
p, _, err := d.parsePriority(line)
if err != nil {
t.Fatalf("got an err: %v", err)
}
if p.Severity != syslog.LOG_INFO {
t.Fatalf("expected severity: %v, got: %v", syslog.LOG_INFO, p.Severity)
}
idx := d.logContentIndex(line)
expected := bytes.Index(line, []byte("1:C 10 Feb 18:16:43.391"))
if idx != expected {
t.Fatalf("expected idx: %v, got: %v", expected, idx)
}
}

View File

@@ -1,93 +0,0 @@
package logging
import (
"bufio"
"net"
"sync"
hclog "github.com/hashicorp/go-hclog"
)
// SyslogServer is a server which listens to syslog messages and parses them
type SyslogServer struct {
listener net.Listener
messages chan *SyslogMessage
parser *DockerLogParser
doneCh chan interface{}
done bool
doneLock sync.Mutex
logger hclog.Logger
}
// NewSyslogServer creates a new syslog server
func NewSyslogServer(l net.Listener, messages chan *SyslogMessage, logger hclog.Logger) *SyslogServer {
logger = logger.Named("logcollector.server")
parser := NewDockerLogParser(logger)
return &SyslogServer{
listener: l,
messages: messages,
parser: parser,
logger: logger,
doneCh: make(chan interface{}),
}
}
// Start starts accepting syslog connections
func (s *SyslogServer) Start() {
for {
select {
case <-s.doneCh:
return
default:
connection, err := s.listener.Accept()
if err != nil {
s.doneLock.Lock()
done := s.done
s.doneLock.Unlock()
if done {
return
}
s.logger.Error("error in accepting connection", "err", err)
continue
}
go s.read(connection)
}
}
}
// read reads the bytes from a connection
func (s *SyslogServer) read(connection net.Conn) {
defer connection.Close()
scanner := bufio.NewScanner(bufio.NewReader(connection))
for {
select {
case <-s.doneCh:
return
default:
}
if scanner.Scan() {
b := scanner.Bytes()
msg := s.parser.Parse(b)
s.messages <- msg
} else {
return
}
}
}
// Shutdown the syslog server
func (s *SyslogServer) Shutdown() {
s.doneLock.Lock()
defer s.doneLock.Unlock()
if !s.done {
close(s.doneCh)
close(s.messages)
s.done = true
s.listener.Close()
}
}

View File

@@ -1,66 +0,0 @@
package logging
import (
"io/ioutil"
"net"
"os"
"path"
"testing"
"time"
"github.com/hashicorp/nomad/helper/testlog"
)
func TestSyslogServer_Start_Shutdown(t *testing.T) {
t.Parallel()
dir, err := ioutil.TempDir("", "sock")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
sock := path.Join(dir, "socket")
defer os.Remove(sock)
l, err := net.Listen("unix", sock)
if err != nil {
t.Fatalf("Failed to listen unix socket: %v", err)
}
s := NewSyslogServer(l, make(chan *SyslogMessage, 2048), testlog.HCLogger(t))
go s.Start()
if s.done {
t.Fatalf("expected running SyslogServer, but not running")
}
received := false
go func() {
for range s.messages {
received = true
}
}()
conn, err := net.Dial("unix", sock)
if err != nil {
t.Fatalf("expected access to SyslogServer, but %v", err)
}
_, err = conn.Write([]byte("syslog server test\n"))
if err != nil {
t.Fatalf("expected send data to SyslogServer but: %v", err)
}
// Need to wait until SyslogServer received the data certainly
time.Sleep(1000 * time.Millisecond)
if !received {
t.Fatalf("expected SyslogServer received data, but not received")
}
defer conn.Close()
s.Shutdown()
if !s.done {
t.Fatalf("expected SyslogServer done, but running")
}
}

View File

@@ -1,206 +0,0 @@
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package logging
import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"runtime"
syslog "github.com/RackSec/srslog"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/nomad/structs"
)
// LogCollectorContext holds context to configure the syslog server
type LogCollectorContext struct {
// TaskName is the name of the Task
TaskName string
// AllocDir is the handle to do operations on the alloc dir of
// the task
AllocDir *allocdir.AllocDir
// LogConfig provides configuration related to log rotation
LogConfig *structs.LogConfig
// PortUpperBound is the upper bound of the ports that we can use to start
// the syslog server
PortUpperBound uint
// PortLowerBound is the lower bound of the ports that we can use to start
// the syslog server
PortLowerBound uint
}
// SyslogCollectorState holds the address and isolation information of a launched
// syslog server
type SyslogCollectorState struct {
Addr string
}
// LogCollector is an interface which allows a driver to launch a log server
// and update log configuration
type LogCollector interface {
LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error)
Exit() error
UpdateLogConfig(logConfig *structs.LogConfig) error
}
// SyslogCollector is a LogCollector which starts a syslog server and does
// rotation to incoming stream
type SyslogCollector struct {
ctx *LogCollectorContext
lro *FileRotator
lre *FileRotator
server *SyslogServer
syslogChan chan *SyslogMessage
taskDir string
logger hclog.Logger
}
// NewSyslogCollector returns an implementation of the SyslogCollector
func NewSyslogCollector(logger hclog.Logger) *SyslogCollector {
return &SyslogCollector{logger: logger.Named("syslog-server"),
syslogChan: make(chan *SyslogMessage, 2048)}
}
// LaunchCollector launches a new syslog server and starts writing log lines to
// files and rotates them
func (s *SyslogCollector) LaunchCollector(ctx *LogCollectorContext) (*SyslogCollectorState, error) {
l, err := s.getListener(ctx.PortLowerBound, ctx.PortUpperBound)
if err != nil {
return nil, err
}
s.logger.Debug("launching syslog server on addr", "addr", l.Addr().String())
s.ctx = ctx
// configuring the task dir
if err := s.configureTaskDir(); err != nil {
return nil, err
}
s.server = NewSyslogServer(l, s.syslogChan, s.logger)
go s.server.Start()
logFileSize := int64(ctx.LogConfig.MaxFileSizeMB * 1024 * 1024)
//FIXME There's an easier way to get this
logdir := ctx.AllocDir.TaskDirs[ctx.TaskName].LogDir
lro, err := NewFileRotator(logdir, fmt.Sprintf("%v.stdout", ctx.TaskName),
ctx.LogConfig.MaxFiles, logFileSize, s.logger)
if err != nil {
return nil, err
}
s.lro = lro
lre, err := NewFileRotator(logdir, fmt.Sprintf("%v.stderr", ctx.TaskName),
ctx.LogConfig.MaxFiles, logFileSize, s.logger)
if err != nil {
return nil, err
}
s.lre = lre
go s.collectLogs(lre, lro)
syslogAddr := fmt.Sprintf("%s://%s", l.Addr().Network(), l.Addr().String())
return &SyslogCollectorState{Addr: syslogAddr}, nil
}
func (s *SyslogCollector) collectLogs(we io.Writer, wo io.Writer) {
for logParts := range s.syslogChan {
// If the severity of the log line is err then we write to stderr
// otherwise all messages go to stdout
if logParts.Severity == syslog.LOG_ERR {
s.lre.Write(logParts.Message)
s.lre.Write([]byte{'\n'})
} else {
s.lro.Write(logParts.Message)
s.lro.Write([]byte{'\n'})
}
}
}
// Exit kills the syslog server
func (s *SyslogCollector) Exit() error {
s.server.Shutdown()
s.lre.Close()
s.lro.Close()
return nil
}
// UpdateLogConfig updates the log configuration
func (s *SyslogCollector) UpdateLogConfig(logConfig *structs.LogConfig) error {
s.ctx.LogConfig = logConfig
if s.lro == nil {
return fmt.Errorf("log rotator for stdout doesn't exist")
}
s.lro.MaxFiles = logConfig.MaxFiles
s.lro.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)
if s.lre == nil {
return fmt.Errorf("log rotator for stderr doesn't exist")
}
s.lre.MaxFiles = logConfig.MaxFiles
s.lre.FileSize = int64(logConfig.MaxFileSizeMB * 1024 * 1024)
return nil
}
// configureTaskDir sets the task dir in the SyslogCollector
func (s *SyslogCollector) configureTaskDir() error {
taskDir, ok := s.ctx.AllocDir.TaskDirs[s.ctx.TaskName]
if !ok {
return fmt.Errorf("couldn't find task directory for task %v", s.ctx.TaskName)
}
s.taskDir = taskDir.Dir
return nil
}
// getFreePort returns a free port ready to be listened on between upper and
// lower bounds
func (s *SyslogCollector) getListener(lowerBound uint, upperBound uint) (net.Listener, error) {
if runtime.GOOS == "windows" {
return s.listenerTCP(lowerBound, upperBound)
}
return s.listenerUnix()
}
// listenerTCP creates a TCP listener using an unused port between an upper and
// lower bound
func (s *SyslogCollector) listenerTCP(lowerBound uint, upperBound uint) (net.Listener, error) {
for i := lowerBound; i <= upperBound; i++ {
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("localhost:%v", i))
if err != nil {
return nil, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
continue
}
return l, nil
}
return nil, fmt.Errorf("No free port found")
}
// listenerUnix creates a Unix domain socket
func (s *SyslogCollector) listenerUnix() (net.Listener, error) {
f, err := ioutil.TempFile("", "plugin")
if err != nil {
return nil, err
}
path := f.Name()
if err := f.Close(); err != nil {
return nil, err
}
if err := os.Remove(path); err != nil {
return nil, err
}
return net.Listen("unix", path)
}

View File

@@ -1,50 +0,0 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at [sirsean@gmail.com]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/

View File

@@ -1,27 +0,0 @@
Copyright (c) 2015 Rackspace. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,131 +0,0 @@
[![Build Status](https://travis-ci.org/RackSec/srslog.svg?branch=master)](https://travis-ci.org/RackSec/srslog)
# srslog
Go has a `syslog` package in the standard library, but it has the following
shortcomings:
1. It doesn't have TLS support
2. [According to bradfitz on the Go team, it is no longer being maintained.](https://github.com/golang/go/issues/13449#issuecomment-161204716)
I agree that it doesn't need to be in the standard library. So, I've
followed Brad's suggestion and have made a separate project to handle syslog.
This code was taken directly from the Go project as a base to start from.
However, this _does_ have TLS support.
# Usage
Basic usage retains the same interface as the original `syslog` package. We
only added to the interface where required to support new functionality.
Switch from the standard library:
```
import(
//"log/syslog"
syslog "github.com/RackSec/srslog"
)
```
You can still use it for local syslog:
```
w, err := syslog.Dial("", "", syslog.LOG_ERR, "testtag")
```
Or to unencrypted UDP:
```
w, err := syslog.Dial("udp", "192.168.0.50:514", syslog.LOG_ERR, "testtag")
```
Or to unencrypted TCP:
```
w, err := syslog.Dial("tcp", "192.168.0.51:514", syslog.LOG_ERR, "testtag")
```
But now you can also send messages via TLS-encrypted TCP:
```
w, err := syslog.DialWithTLSCertPath("tcp+tls", "192.168.0.52:514", syslog.LOG_ERR, "testtag", "/path/to/servercert.pem")
```
And if you need more control over your TLS configuration :
```
pool := x509.NewCertPool()
serverCert, err := ioutil.ReadFile("/path/to/servercert.pem")
if err != nil {
return nil, err
}
pool.AppendCertsFromPEM(serverCert)
config := tls.Config{
RootCAs: pool,
}
w, err := DialWithTLSConfig(network, raddr, priority, tag, &config)
```
(Note that in both TLS cases, this uses a self-signed certificate, where the
remote syslog server has the keypair and the client has only the public key.)
And then to write log messages, continue like so:
```
if err != nil {
log.Fatal("failed to connect to syslog:", err)
}
defer w.Close()
w.Alert("this is an alert")
w.Crit("this is critical")
w.Err("this is an error")
w.Warning("this is a warning")
w.Notice("this is a notice")
w.Info("this is info")
w.Debug("this is debug")
w.Write([]byte("these are some bytes"))
```
# Generating TLS Certificates
We've provided a script that you can use to generate a self-signed keypair:
```
pip install cryptography
python script/gen-certs.py
```
That outputs the public key and private key to standard out. Put those into
`.pem` files. (And don't put them into any source control. The certificate in
the `test` directory is used by the unit tests, and please do not actually use
it anywhere else.)
# Running Tests
Run the tests as usual:
```
go test
```
But we've also provided a test coverage script that will show you which
lines of code are not covered:
```
script/coverage --html
```
That will open a new browser tab showing coverage information.
# License
This project uses the New BSD License, the same as the Go project itself.
# Code of Conduct
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.

View File

@@ -1,68 +0,0 @@
package srslog
import (
"errors"
)
// Priority is a combination of the syslog facility and
// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
// message from the FTP facility. The default severity is LOG_EMERG;
// the default facility is LOG_KERN.
type Priority int
const severityMask = 0x07
const facilityMask = 0xf8
const (
// Severity.
// From /usr/include/sys/syslog.h.
// These are the same on Linux, BSD, and OS X.
LOG_EMERG Priority = iota
LOG_ALERT
LOG_CRIT
LOG_ERR
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
)
const (
// Facility.
// From /usr/include/sys/syslog.h.
// These are the same up to LOG_FTP on Linux, BSD, and OS X.
LOG_KERN Priority = iota << 3
LOG_USER
LOG_MAIL
LOG_DAEMON
LOG_AUTH
LOG_SYSLOG
LOG_LPR
LOG_NEWS
LOG_UUCP
LOG_CRON
LOG_AUTHPRIV
LOG_FTP
_ // unused
_ // unused
_ // unused
_ // unused
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
LOG_LOCAL5
LOG_LOCAL6
LOG_LOCAL7
)
func validatePriority(p Priority) error {
if p < 0 || p > LOG_LOCAL7|LOG_DEBUG {
return errors.New("log/syslog: invalid priority")
} else {
return nil
}
}

View File

@@ -1,87 +0,0 @@
package srslog
import (
"crypto/tls"
"net"
)
// dialerFunctionWrapper is a simple object that consists of a dialer function
// and its name. This is primarily for testing, so we can make sure that the
// getDialer method returns the correct dialer function. However, if you ever
// find that you need to check which dialer function you have, this would also
// be useful for you without having to use reflection.
type dialerFunctionWrapper struct {
Name string
Dialer func() (serverConn, string, error)
}
// Call the wrapped dialer function and return its return values.
func (df dialerFunctionWrapper) Call() (serverConn, string, error) {
return df.Dialer()
}
// getDialer returns a "dialer" function that can be called to connect to a
// syslog server.
//
// Each dialer function is responsible for dialing the remote host and returns
// a serverConn, the hostname (or a default if the Writer has not specified a
// hostname), and an error in case dialing fails.
//
// The reason for separate dialers is that different network types may need
// to dial their connection differently, yet still provide a net.Conn interface
// that you can use once they have dialed. Rather than an increasingly long
// conditional, we have a map of network -> dialer function (with a sane default
// value), and adding a new network type is as easy as writing the dialer
// function and adding it to the map.
func (w *Writer) getDialer() dialerFunctionWrapper {
dialers := map[string]dialerFunctionWrapper{
"": dialerFunctionWrapper{"unixDialer", w.unixDialer},
"tcp+tls": dialerFunctionWrapper{"tlsDialer", w.tlsDialer},
}
dialer, ok := dialers[w.network]
if !ok {
dialer = dialerFunctionWrapper{"basicDialer", w.basicDialer}
}
return dialer
}
// unixDialer uses the unixSyslog method to open a connection to the syslog
// daemon running on the local machine.
func (w *Writer) unixDialer() (serverConn, string, error) {
sc, err := unixSyslog()
hostname := w.hostname
if hostname == "" {
hostname = "localhost"
}
return sc, hostname, err
}
// tlsDialer connects to TLS over TCP, and is used for the "tcp+tls" network
// type.
func (w *Writer) tlsDialer() (serverConn, string, error) {
c, err := tls.Dial("tcp", w.raddr, w.tlsConfig)
var sc serverConn
hostname := w.hostname
if err == nil {
sc = &netConn{conn: c}
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return sc, hostname, err
}
// basicDialer is the most common dialer for syslog, and supports both TCP and
// UDP connections.
func (w *Writer) basicDialer() (serverConn, string, error) {
c, err := net.Dial(w.network, w.raddr)
var sc serverConn
hostname := w.hostname
if err == nil {
sc = &netConn{conn: c}
if hostname == "" {
hostname = c.LocalAddr().String()
}
}
return sc, hostname, err
}

View File

@@ -1,48 +0,0 @@
package srslog
import (
"fmt"
"os"
"time"
)
// Formatter is a type of function that takes the consituent parts of a
// syslog message and returns a formatted string. A different Formatter is
// defined for each different syslog protocol we support.
type Formatter func(p Priority, hostname, tag, content string) string
// DefaultFormatter is the original format supported by the Go syslog package,
// and is a non-compliant amalgamation of 3164 and 5424 that is intended to
// maximize compatibility.
func DefaultFormatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.RFC3339)
msg := fmt.Sprintf("<%d> %s %s %s[%d]: %s",
p, timestamp, hostname, tag, os.Getpid(), content)
return msg
}
// UnixFormatter omits the hostname, because it is only used locally.
func UnixFormatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.Stamp)
msg := fmt.Sprintf("<%d>%s %s[%d]: %s",
p, timestamp, tag, os.Getpid(), content)
return msg
}
// RFC3164Formatter provides an RFC 3164 compliant message.
func RFC3164Formatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.Stamp)
msg := fmt.Sprintf("<%d> %s %s %s[%d]: %s",
p, timestamp, hostname, tag, os.Getpid(), content)
return msg
}
// RFC5424Formatter provides an RFC 5424 compliant message.
func RFC5424Formatter(p Priority, hostname, tag, content string) string {
timestamp := time.Now().Format(time.RFC3339)
pid := os.Getpid()
appName := os.Args[0]
msg := fmt.Sprintf("<%d>%d %s %s %s %d %s %s",
p, 1, timestamp, hostname, appName, pid, tag, content)
return msg
}

View File

@@ -1,24 +0,0 @@
package srslog
import (
"fmt"
)
// Framer is a type of function that takes an input string (typically an
// already-formatted syslog message) and applies "message framing" to it. We
// have different framers because different versions of the syslog protocol
// and its transport requirements define different framing behavior.
type Framer func(in string) string
// DefaultFramer does nothing, since there is no framing to apply. This is
// the original behavior of the Go syslog package, and is also typically used
// for UDP syslog.
func DefaultFramer(in string) string {
return in
}
// RFC5425MessageLengthFramer prepends the message length to the front of the
// provided message, as defined in RFC 5425.
func RFC5425MessageLengthFramer(in string) string {
return fmt.Sprintf("%d %s", len(in), in)
}

View File

@@ -1,30 +0,0 @@
package srslog
import (
"net"
)
// netConn has an internal net.Conn and adheres to the serverConn interface,
// allowing us to send syslog messages over the network.
type netConn struct {
conn net.Conn
}
// writeString formats syslog messages using time.RFC3339 and includes the
// hostname, and sends the message to the connection.
func (n *netConn) writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, msg string) error {
if framer == nil {
framer = DefaultFramer
}
if formatter == nil {
formatter = DefaultFormatter
}
formattedMessage := framer(formatter(p, hostname, tag, msg))
_, err := n.conn.Write([]byte(formattedMessage))
return err
}
// close the network connection
func (n *netConn) close() error {
return n.conn.Close()
}

View File

@@ -1,100 +0,0 @@
package srslog
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"os"
)
// This interface allows us to work with both local and network connections,
// and enables Solaris support (see syslog_unix.go).
type serverConn interface {
writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, s string) error
close() error
}
// New establishes a new connection to the system log daemon. Each
// write to the returned Writer sends a log message with the given
// priority and prefix.
func New(priority Priority, tag string) (w *Writer, err error) {
return Dial("", "", priority, tag)
}
// Dial establishes a connection to a log daemon by connecting to
// address raddr on the specified network. Each write to the returned
// Writer sends a log message with the given facility, severity and
// tag.
// If network is empty, Dial will connect to the local syslog server.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
return DialWithTLSConfig(network, raddr, priority, tag, nil)
}
// DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses certPath to load TLS certificates and configure
// the secure connection.
func DialWithTLSCertPath(network, raddr string, priority Priority, tag, certPath string) (*Writer, error) {
serverCert, err := ioutil.ReadFile(certPath)
if err != nil {
return nil, err
}
return DialWithTLSCert(network, raddr, priority, tag, serverCert)
}
// DialWIthTLSCert establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses serverCert to load a TLS certificate
// and configure the secure connection.
func DialWithTLSCert(network, raddr string, priority Priority, tag string, serverCert []byte) (*Writer, error) {
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(serverCert)
config := tls.Config{
RootCAs: pool,
}
return DialWithTLSConfig(network, raddr, priority, tag, &config)
}
// DialWithTLSConfig establishes a secure connection to a log daemon by connecting to
// address raddr on the specified network. It uses tlsConfig to configure the secure connection.
func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) {
if err := validatePriority(priority); err != nil {
return nil, err
}
if tag == "" {
tag = os.Args[0]
}
hostname, _ := os.Hostname()
w := &Writer{
priority: priority,
tag: tag,
hostname: hostname,
network: network,
raddr: raddr,
tlsConfig: tlsConfig,
}
w.Lock()
defer w.Unlock()
err := w.connect()
if err != nil {
return nil, err
}
return w, err
}
// NewLogger creates a log.Logger whose output is written to
// the system log service with the specified priority. The logFlag
// argument is the flag set passed through to log.New to create
// the Logger.
func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
s, err := New(p, "")
if err != nil {
return nil, err
}
return log.New(s, "", logFlag), nil
}

View File

@@ -1,54 +0,0 @@
package srslog
import (
"errors"
"io"
"net"
)
// unixSyslog opens a connection to the syslog daemon running on the
// local machine using a Unix domain socket. This function exists because of
// Solaris support as implemented by gccgo. On Solaris you can not
// simply open a TCP connection to the syslog daemon. The gccgo
// sources have a syslog_solaris.go file that implements unixSyslog to
// return a type that satisfies the serverConn interface and simply calls the C
// library syslog function.
func unixSyslog() (conn serverConn, err error) {
logTypes := []string{"unixgram", "unix"}
logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
for _, network := range logTypes {
for _, path := range logPaths {
conn, err := net.Dial(network, path)
if err != nil {
continue
} else {
return &localConn{conn: conn}, nil
}
}
}
return nil, errors.New("Unix syslog delivery error")
}
// localConn adheres to the serverConn interface, allowing us to send syslog
// messages to the local syslog daemon over a Unix domain socket.
type localConn struct {
conn io.WriteCloser
}
// writeString formats syslog messages using time.Stamp instead of time.RFC3339,
// and omits the hostname (because it is expected to be used locally).
func (n *localConn) writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, msg string) error {
if framer == nil {
framer = DefaultFramer
}
if formatter == nil {
formatter = UnixFormatter
}
_, err := n.conn.Write([]byte(framer(formatter(p, hostname, tag, msg))))
return err
}
// close the (local) network connection
func (n *localConn) close() error {
return n.conn.Close()
}

View File

@@ -1,164 +0,0 @@
package srslog
import (
"crypto/tls"
"strings"
"sync"
)
// A Writer is a connection to a syslog server.
type Writer struct {
sync.Mutex // guards conn
priority Priority
tag string
hostname string
network string
raddr string
tlsConfig *tls.Config
framer Framer
formatter Formatter
conn serverConn
}
// connect makes a connection to the syslog server.
// It must be called with w.mu held.
func (w *Writer) connect() (err error) {
if w.conn != nil {
// ignore err from close, it makes sense to continue anyway
w.conn.close()
w.conn = nil
}
var conn serverConn
var hostname string
dialer := w.getDialer()
conn, hostname, err = dialer.Call()
if err == nil {
w.conn = conn
w.hostname = hostname
}
return
}
// SetFormatter changes the formatter function for subsequent messages.
func (w *Writer) SetFormatter(f Formatter) {
w.formatter = f
}
// SetFramer changes the framer function for subsequent messages.
func (w *Writer) SetFramer(f Framer) {
w.framer = f
}
// Write sends a log message to the syslog daemon using the default priority
// passed into `srslog.New` or the `srslog.Dial*` functions.
func (w *Writer) Write(b []byte) (int, error) {
return w.writeAndRetry(w.priority, string(b))
}
// Close closes a connection to the syslog daemon.
func (w *Writer) Close() error {
w.Lock()
defer w.Unlock()
if w.conn != nil {
err := w.conn.close()
w.conn = nil
return err
}
return nil
}
// Emerg logs a message with severity LOG_EMERG; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Emerg(m string) (err error) {
_, err = w.writeAndRetry(LOG_EMERG, m)
return err
}
// Alert logs a message with severity LOG_ALERT; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Alert(m string) (err error) {
_, err = w.writeAndRetry(LOG_ALERT, m)
return err
}
// Crit logs a message with severity LOG_CRIT; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Crit(m string) (err error) {
_, err = w.writeAndRetry(LOG_CRIT, m)
return err
}
// Err logs a message with severity LOG_ERR; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Err(m string) (err error) {
_, err = w.writeAndRetry(LOG_ERR, m)
return err
}
// Warning logs a message with severity LOG_WARNING; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Warning(m string) (err error) {
_, err = w.writeAndRetry(LOG_WARNING, m)
return err
}
// Notice logs a message with severity LOG_NOTICE; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Notice(m string) (err error) {
_, err = w.writeAndRetry(LOG_NOTICE, m)
return err
}
// Info logs a message with severity LOG_INFO; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Info(m string) (err error) {
_, err = w.writeAndRetry(LOG_INFO, m)
return err
}
// Debug logs a message with severity LOG_DEBUG; this overrides the default
// priority passed to `srslog.New` and the `srslog.Dial*` functions.
func (w *Writer) Debug(m string) (err error) {
_, err = w.writeAndRetry(LOG_DEBUG, m)
return err
}
func (w *Writer) writeAndRetry(p Priority, s string) (int, error) {
pr := (w.priority & facilityMask) | (p & severityMask)
w.Lock()
defer w.Unlock()
if w.conn != nil {
if n, err := w.write(pr, s); err == nil {
return n, err
}
}
if err := w.connect(); err != nil {
return 0, err
}
return w.write(pr, s)
}
// write generates and writes a syslog formatted string. It formats the
// message based on the current Formatter and Framer.
func (w *Writer) write(p Priority, msg string) (int, error) {
// ensure it ends in a \n
if !strings.HasSuffix(msg, "\n") {
msg += "\n"
}
err := w.conn.writeString(w.framer, w.formatter, p, w.hostname, w.tag, msg)
if err != nil {
return 0, err
}
// Note: return the length of the input, not the number of
// bytes printed by Fprintf, because this must behave like
// an io.Writer.
return len(msg), nil
}

1
vendor/vendor.json vendored
View File

@@ -13,7 +13,6 @@
{"path":"github.com/NVIDIA/gpu-monitoring-tools/bindings/go/nvml","checksumSHA1":"P8FATSSgpe5A17FyPrGpsX95Xw8=","revision":"86f2a9fac6c5b597dc494420005144b8ef7ec9fb","revisionTime":"2018-08-29T22:20:09Z"},
{"path":"github.com/NYTimes/gziphandler","checksumSHA1":"jktW57+vJsziNVPeXMCoujTzdW4=","revision":"97ae7fbaf81620fe97840685304a78a306a39c64","revisionTime":"2017-09-16T00:36:49Z"},
{"path":"github.com/Nvveen/Gotty","checksumSHA1":"Aqy8/FoAIidY/DeQ5oTYSZ4YFVc=","revision":"cd527374f1e5bff4938207604a14f2e38a9cf512","revisionTime":"2012-06-04T00:48:16Z"},
{"path":"github.com/RackSec/srslog","checksumSHA1":"GkeYcZh0B14rtg15JAVDPVwjNoY=","revision":"259aed10dfa74ea2961eddd1d9847619f6e98837","revisionTime":"2016-01-20T22:33:50Z"},
{"path":"github.com/StackExchange/wmi","checksumSHA1":"qtjd74+bErubh+qyv3s+lWmn9wc=","revision":"ea383cf3ba6ec950874b8486cd72356d007c768f","revisionTime":"2017-04-10T19:29:09Z"},
{"path":"github.com/agext/levenshtein","checksumSHA1":"jQh1fnoKPKMURvKkpdRjN695nAQ=","revision":"5f10fee965225ac1eecdc234c09daf5cd9e7f7b6","revisionTime":"2017-02-17T06:30:20Z"},
{"path":"github.com/apparentlymart/go-textseg/textseg","checksumSHA1":"Ffhtm8iHH7l2ynVVOIGJE3eiuLA=","revision":"b836f5c4d331d1945a2fead7188db25432d73b69","revisionTime":"2017-05-31T20:39:52Z"},