runc/patch/0008-runc-runc-logs-forwarding-to-syslog.patch
2023-09-06 16:18:19 +08:00

726 lines
22 KiB
Diff

From 10536f71def2026279285999779023d98f505e56 Mon Sep 17 00:00:00 2001
From: panwenxing <panwenxing@huawei.com>
Date: Fri, 19 Oct 2018 15:00:34 +0800
Subject: [PATCH] runc: runc logs forwarding to syslog
reason:runc logs forwarding to syslog and using the config "--log-level" to control the number of logs
Change-Id: Ia93f6f5c56131ea8558c4b7b7e5c4bec827a1bad
Conflicts:
libcontainer/container_linux.go
libcontainer/process_linux.go
libcontainer/state_linux.go
---
create.go | 2 +-
libcontainer/configs/config.go | 70 +++++++++---
libcontainer/container_linux.go | 2 +-
main.go | 20 ++++
vendor/github.com/sirupsen/logrus/Checklist | 1 +
.../logrus/hooks/airbrake/airbrake.go | 54 ++++++++++
.../sirupsen/logrus/hooks/bugsnag/bugsnag.go | 68 ++++++++++++
.../logrus/hooks/papertrail/README.md | 28 +++++
.../logrus/hooks/papertrail/papertrail.go | 55 ++++++++++
.../sirupsen/logrus/hooks/sentry/README.md | 61 +++++++++++
.../sirupsen/logrus/hooks/sentry/sentry.go | 100 ++++++++++++++++++
.../sirupsen/logrus/hooks/syslog/README.md | 20 ++++
.../sirupsen/logrus/hooks/syslog/syslog.go | 59 +++++++++++
13 files changed, 523 insertions(+), 17 deletions(-)
create mode 100644 vendor/github.com/sirupsen/logrus/Checklist
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/airbrake/airbrake.go
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/bugsnag/bugsnag.go
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/papertrail/README.md
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/papertrail/papertrail.go
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/sentry/README.md
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/sentry/sentry.go
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/syslog/README.md
create mode 100644 vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
diff --git a/create.go b/create.go
index 97854b8..46ef1ef 100644
--- a/create.go
+++ b/create.go
@@ -2,9 +2,9 @@ package main
import (
"fmt"
- "os"
"github.com/urfave/cli"
+ "os"
)
var createCommand = cli.Command{
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 72910ff..9076846 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -4,15 +4,22 @@ import (
"bytes"
"encoding/json"
"fmt"
- "os/exec"
- "time"
-
"github.com/sirupsen/logrus"
-
"github.com/opencontainers/runc/libcontainer/devices"
"github.com/opencontainers/runtime-spec/specs-go"
+ "os/exec"
+ "time"
+)
+
+const (
+ minHookTimeOut = 0
+ defaultHookTimeOut = 5 * time.Second
+ maxHookTimeOut = 120 * time.Second
+ //the runc default timeout is 120s, so set the defaultWarnTime to 80% of the default timeout.
+ defaultWarnTime = 96 * time.Second
)
+
type Rlimit struct {
Type int `json:"type"`
Hard uint64 `json:"hard"`
@@ -279,11 +286,11 @@ type Capabilities struct {
func (hooks HookList) RunHooks(state *specs.State) error {
for i, h := range hooks {
- logrus.Infof("run hooks %d:%T", i, h)
+ logrus.Infof("run hooks %d:%T, ContainerId: %s", i, h, state.ID)
if err := h.Run(state); err != nil {
- return fmt.Errorf("error running hook #%d: %w", i, err)
+ return fmt.Errorf("error running hook #%d: %w, ContainerId: %s", i, err, state.ID)
}
- logrus.Infof("hooks %d:%T done", i, h)
+ logrus.Infof("hooks %d:%T done, ContainerId: %s", i, h, state.ID)
}
return nil
@@ -388,29 +395,62 @@ func (c Command) Run(s *specs.State) error {
Stdout: &stdout,
Stderr: &stderr,
}
+ startTime := time.Now()
if err := cmd.Start(); err != nil {
return err
}
+ if c.Timeout != nil && *c.Timeout <= minHookTimeOut {
+ *c.Timeout = defaultHookTimeOut
+ logrus.Warnf("hook timeout should not be negative or zero, set hook timeout as 5s")
+ }
+ if c.Timeout != nil && *c.Timeout > maxHookTimeOut {
+ logrus.Warnf("hook timeout: %s is too long, use 120s as timeout. ContainerID: %s", *c.Timeout, s.ID)
+ *c.Timeout = maxHookTimeOut
+ }
errC := make(chan error, 1)
+ var (
+ timerCh <-chan time.Time
+ warnTime = defaultWarnTime.Seconds()
+ )
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("error running hook: %w, stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
+ elapsedTime := time.Since(startTime)
+ logrus.Infof("hook spends time %s, ContainerID: %s", elapsedTime, s.ID)
+ if c.Timeout != nil {
+ if elapsedTime.Seconds() >= (c.Timeout.Seconds() * 0.8) {
+ logrus.Warnf("elapsed %s, more than 80%% of the timeout %s, ContainerID: %s", elapsedTime, c.Timeout, s.ID)
+ }
+ } else {
+ if elapsedTime.Seconds() >= warnTime {
+ logrus.Warnf("elapsed %s, more than 80%% of the default timeout 120s, ContainerID: %s", elapsedTime, s.ID)
+ }
+ }
errC <- err
}()
- var timerCh <-chan time.Time
if c.Timeout != nil {
timer := time.NewTimer(*c.Timeout)
defer timer.Stop()
timerCh = timer.C
+ warnTime = (*c.Timeout).Seconds() * 0.8
}
- select {
- case err := <-errC:
- return err
- case <-timerCh:
- _ = cmd.Process.Kill()
- <-errC
- return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
+ timeAfter := time.After(time.Duration(warnTime) * time.Second)
+ for {
+ select {
+ case err := <-errC:
+ return err
+ case <-timerCh:
+ cmd.Process.Kill()
+ cmd.Wait()
+ return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
+ case <-timeAfter:
+ if c.Timeout != nil {
+ logrus.Warnf("hook ran more than 80%% of the timeout %s, ContainerID: %s", *c.Timeout, s.ID)
+ } else {
+ logrus.Warnf("hook ran more than 80%% of the default timeout 120s, ContainerID: %s", s.ID)
+ }
+ }
}
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index f8ce1cc..8fbd04d 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -370,7 +370,7 @@ func (c *linuxContainer) start(process *Process) (retErr error) {
if err := c.config.Hooks[configs.Poststart].RunHooks(s); err != nil {
if err := ignoreTerminateErrors(parent.terminate()); err != nil {
- logrus.Warn(fmt.Errorf("error running poststart hook: %w", err))
+ logrus.Warn(fmt.Errorf("error running poststart hook: %w, ContainerId: %s", err, s.ID))
}
return err
}
diff --git a/main.go b/main.go
index 4d66638..9e14976 100644
--- a/main.go
+++ b/main.go
@@ -100,6 +100,10 @@ func main() {
Value: root,
Usage: "root directory for storage of container state (this should be located in tmpfs)",
},
+ cli.StringFlag{
+ Name: "log-level",
+ Usage: "set the logging level [debug, info, warn, error, fatal, panic]",
+ },
cli.StringFlag{
Name: "criu",
Value: "criu",
@@ -211,7 +215,23 @@ func configLogrus(context *cli.Context) error {
return err
}
logrus.SetOutput(f)
+ hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
+ if serr != nil {
+ fmt.Fprint(f, fmt.Sprintf("Leo: new syslog hook get %s", serr))
+ }
+ logrus.AddHook(hook)
+ }
+ if logLevel := context.GlobalString("log-level"); logLevel != "" {
+ lvl, err := logrus.ParseLevel(logLevel)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel)
+ os.Exit(1)
+ }
+ logrus.SetLevel(lvl)
}
+ if context.GlobalBool("debug") {
+ logrus.SetLevel(logrus.DebugLevel)
+ }
return nil
}
diff --git a/vendor/github.com/sirupsen/logrus/Checklist b/vendor/github.com/sirupsen/logrus/Checklist
new file mode 100644
index 0000000..7117b24
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/Checklist
@@ -0,0 +1 @@
+imported from runc v1.0.0-Release Candidate 2: Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks
diff --git a/vendor/github.com/sirupsen/logrus/hooks/airbrake/airbrake.go b/vendor/github.com/sirupsen/logrus/hooks/airbrake/airbrake.go
new file mode 100644
index 0000000..b0502c3
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/airbrake/airbrake.go
@@ -0,0 +1,54 @@
+package airbrake
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/tobi/airbrake-go"
+)
+
+// AirbrakeHook to send exceptions to an exception-tracking service compatible
+// with the Airbrake API.
+type airbrakeHook struct {
+ APIKey string
+ Endpoint string
+ Environment string
+}
+
+func NewHook(endpoint, apiKey, env string) *airbrakeHook {
+ return &airbrakeHook{
+ APIKey: apiKey,
+ Endpoint: endpoint,
+ Environment: env,
+ }
+}
+
+func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
+ airbrake.ApiKey = hook.APIKey
+ airbrake.Endpoint = hook.Endpoint
+ airbrake.Environment = hook.Environment
+
+ var notifyErr error
+ err, ok := entry.Data["error"].(error)
+ if ok {
+ notifyErr = err
+ } else {
+ notifyErr = errors.New(entry.Message)
+ }
+
+ airErr := airbrake.Notify(notifyErr)
+ if airErr != nil {
+ return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
+ }
+
+ return nil
+}
+
+func (hook *airbrakeHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.ErrorLevel,
+ logrus.FatalLevel,
+ logrus.PanicLevel,
+ }
+}
diff --git a/vendor/github.com/sirupsen/logrus/hooks/bugsnag/bugsnag.go b/vendor/github.com/sirupsen/logrus/hooks/bugsnag/bugsnag.go
new file mode 100644
index 0000000..d20a0f5
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/bugsnag/bugsnag.go
@@ -0,0 +1,68 @@
+package logrus_bugsnag
+
+import (
+ "errors"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/bugsnag/bugsnag-go"
+)
+
+type bugsnagHook struct{}
+
+// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
+// bugsnag.Configure. Bugsnag must be configured before the hook.
+var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
+
+// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
+// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
+// failed.
+type ErrBugsnagSendFailed struct {
+ err error
+}
+
+func (e ErrBugsnagSendFailed) Error() string {
+ return "failed to send error to Bugsnag: " + e.err.Error()
+}
+
+// NewBugsnagHook initializes a logrus hook which sends exceptions to an
+// exception-tracking service compatible with the Bugsnag API. Before using
+// this hook, you must call bugsnag.Configure(). The returned object should be
+// registered with a log via `AddHook()`
+//
+// Entries that trigger an Error, Fatal or Panic should now include an "error"
+// field to send to Bugsnag.
+func NewBugsnagHook() (*bugsnagHook, error) {
+ if bugsnag.Config.APIKey == "" {
+ return nil, ErrBugsnagUnconfigured
+ }
+ return &bugsnagHook{}, nil
+}
+
+// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
+// "error" field (or the Message if the error isn't present) and sends it off.
+func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
+ var notifyErr error
+ err, ok := entry.Data["error"].(error)
+ if ok {
+ notifyErr = err
+ } else {
+ notifyErr = errors.New(entry.Message)
+ }
+
+ bugsnagErr := bugsnag.Notify(notifyErr)
+ if bugsnagErr != nil {
+ return ErrBugsnagSendFailed{bugsnagErr}
+ }
+
+ return nil
+}
+
+// Levels enumerates the log levels on which the error should be forwarded to
+// bugsnag: everything at or above the "Error" level.
+func (hook *bugsnagHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.ErrorLevel,
+ logrus.FatalLevel,
+ logrus.PanicLevel,
+ }
+}
diff --git a/vendor/github.com/sirupsen/logrus/hooks/papertrail/README.md b/vendor/github.com/sirupsen/logrus/hooks/papertrail/README.md
new file mode 100644
index 0000000..ae61e92
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/papertrail/README.md
@@ -0,0 +1,28 @@
+# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
+
+[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
+
+In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
+
+## Usage
+
+You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
+
+For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/papertrail"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
diff --git a/vendor/github.com/sirupsen/logrus/hooks/papertrail/papertrail.go b/vendor/github.com/sirupsen/logrus/hooks/papertrail/papertrail.go
new file mode 100644
index 0000000..c0f10c1
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/papertrail/papertrail.go
@@ -0,0 +1,55 @@
+package logrus_papertrail
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+)
+
+const (
+ format = "Jan 2 15:04:05"
+)
+
+// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
+type PapertrailHook struct {
+ Host string
+ Port int
+ AppName string
+ UDPConn net.Conn
+}
+
+// NewPapertrailHook creates a hook to be added to an instance of logger.
+func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
+ conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
+ return &PapertrailHook{host, port, appName, conn}, err
+}
+
+// Fire is called when a log event is fired.
+func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
+ date := time.Now().Format(format)
+ msg, _ := entry.String()
+ payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
+
+ bytesWritten, err := hook.UDPConn.Write([]byte(payload))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
+ return err
+ }
+
+ return nil
+}
+
+// Levels returns the available logging levels.
+func (hook *PapertrailHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ logrus.WarnLevel,
+ logrus.InfoLevel,
+ logrus.DebugLevel,
+ }
+}
diff --git a/vendor/github.com/sirupsen/logrus/hooks/sentry/README.md b/vendor/github.com/sirupsen/logrus/hooks/sentry/README.md
new file mode 100644
index 0000000..19e58bb
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/sentry/README.md
@@ -0,0 +1,61 @@
+# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
+
+[Sentry](https://getsentry.com) provides both self-hosted and hosted
+solutions for exception tracking.
+Both client and server are
+[open source](https://github.com/getsentry/sentry).
+
+## Usage
+
+Every sentry application defined on the server gets a different
+[DSN](https://www.getsentry.com/docs/). In the example below replace
+`YOUR_DSN` with the one created for your application.
+
+```go
+import (
+ "github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/sentry"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ })
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
+
+## Special fields
+
+Some logrus fields have a special meaning in this hook,
+these are server_name and logger.
+When logs are sent to sentry these fields are treated differently.
+- server_name (also known as hostname) is the name of the server which
+is logging the event (hostname.example.com)
+- logger is the part of the application which is logging the event.
+In go this usually means setting it to the name of the package.
+
+## Timeout
+
+`Timeout` is the time the sentry hook will wait for a response
+from the sentry server.
+
+If this time elapses with no response from
+the server an error will be returned.
+
+If `Timeout` is set to 0 the SentryHook will not wait for a reply
+and will assume a correct delivery.
+
+The SentryHook has a default timeout of `100 milliseconds` when created
+with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
+
+```go
+hook, _ := logrus_sentry.NewSentryHook(...)
+hook.Timeout = 20*time.Second
+```
diff --git a/vendor/github.com/sirupsen/logrus/hooks/sentry/sentry.go b/vendor/github.com/sirupsen/logrus/hooks/sentry/sentry.go
new file mode 100644
index 0000000..379f281
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/sentry/sentry.go
@@ -0,0 +1,100 @@
+package logrus_sentry
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/getsentry/raven-go"
+)
+
+var (
+ severityMap = map[logrus.Level]raven.Severity{
+ logrus.DebugLevel: raven.DEBUG,
+ logrus.InfoLevel: raven.INFO,
+ logrus.WarnLevel: raven.WARNING,
+ logrus.ErrorLevel: raven.ERROR,
+ logrus.FatalLevel: raven.FATAL,
+ logrus.PanicLevel: raven.FATAL,
+ }
+)
+
+func getAndDel(d logrus.Fields, key string) (string, bool) {
+ var (
+ ok bool
+ v interface{}
+ val string
+ )
+ if v, ok = d[key]; !ok {
+ return "", false
+ }
+
+ if val, ok = v.(string); !ok {
+ return "", false
+ }
+ delete(d, key)
+ return val, true
+}
+
+// SentryHook delivers logs to a sentry server.
+type SentryHook struct {
+ // Timeout sets the time to wait for a delivery error from the sentry server.
+ // If this is set to zero the server will not wait for any response and will
+ // consider the message correctly sent
+ Timeout time.Duration
+
+ client *raven.Client
+ levels []logrus.Level
+}
+
+// NewSentryHook creates a hook to be added to an instance of logger
+// and initializes the raven client.
+// This method sets the timeout to 100 milliseconds.
+func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
+ client, err := raven.NewClient(DSN, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &SentryHook{100 * time.Millisecond, client, levels}, nil
+}
+
+// Called when an event should be sent to sentry
+// Special fields that sentry uses to give more information to the server
+// are extracted from entry.Data (if they are found)
+// These fields are: logger and server_name
+func (hook *SentryHook) Fire(entry *logrus.Entry) error {
+ packet := &raven.Packet{
+ Message: entry.Message,
+ Timestamp: raven.Timestamp(entry.Time),
+ Level: severityMap[entry.Level],
+ Platform: "go",
+ }
+
+ d := entry.Data
+
+ if logger, ok := getAndDel(d, "logger"); ok {
+ packet.Logger = logger
+ }
+ if serverName, ok := getAndDel(d, "server_name"); ok {
+ packet.ServerName = serverName
+ }
+ packet.Extra = map[string]interface{}(d)
+
+ _, errCh := hook.client.Capture(packet, nil)
+ timeout := hook.Timeout
+ if timeout != 0 {
+ timeoutCh := time.After(timeout)
+ select {
+ case err := <-errCh:
+ return err
+ case <-timeoutCh:
+ return fmt.Errorf("no response from sentry server in %s", timeout)
+ }
+ }
+ return nil
+}
+
+// Levels returns the available logging levels.
+func (hook *SentryHook) Levels() []logrus.Level {
+ return hook.levels
+}
diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md b/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md
new file mode 100644
index 0000000..4dbb8e7
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/README.md
@@ -0,0 +1,20 @@
+# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
+
+## Usage
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
new file mode 100644
index 0000000..b6fa374
--- /dev/null
+++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
@@ -0,0 +1,59 @@
+package logrus_syslog
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+ Writer *syslog.Writer
+ SyslogNetwork string
+ SyslogRaddr string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+ w, err := syslog.Dial(network, raddr, priority, tag)
+ return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.Writer.Crit(line)
+ case logrus.FatalLevel:
+ return hook.Writer.Crit(line)
+ case logrus.ErrorLevel:
+ return hook.Writer.Err(line)
+ case logrus.WarnLevel:
+ return hook.Writer.Warning(line)
+ case logrus.InfoLevel:
+ return hook.Writer.Info(line)
+ case logrus.DebugLevel:
+ return hook.Writer.Debug(line)
+ default:
+ return nil
+ }
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ logrus.WarnLevel,
+ logrus.InfoLevel,
+ logrus.DebugLevel,
+ }
+}
--
2.33.0