summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/wiggin77
diff options
context:
space:
mode:
authorWim <wim@42.be>2020-10-19 23:40:00 +0200
committerGitHub <noreply@github.com>2020-10-19 23:40:00 +0200
commit075a84427f6332aab707d283ad770d69f8816032 (patch)
tree0ff9f56a057919f3fe968e57f6f0b1c0d1f85078 /vendor/github.com/wiggin77
parent950f2759bd2b20aa0bdedc3dc9a74d0dafb606d8 (diff)
downloadmatterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.tar.gz
matterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.tar.bz2
matterbridge-msglm-075a84427f6332aab707d283ad770d69f8816032.zip
Update vendor (#1265)
Diffstat (limited to 'vendor/github.com/wiggin77')
-rw-r--r--vendor/github.com/wiggin77/cfg/.gitignore12
-rw-r--r--vendor/github.com/wiggin77/cfg/.travis.yml5
-rw-r--r--vendor/github.com/wiggin77/cfg/LICENSE21
-rw-r--r--vendor/github.com/wiggin77/cfg/README.md43
-rw-r--r--vendor/github.com/wiggin77/cfg/config.go366
-rw-r--r--vendor/github.com/wiggin77/cfg/go.mod5
-rw-r--r--vendor/github.com/wiggin77/cfg/go.sum2
-rw-r--r--vendor/github.com/wiggin77/cfg/ini/ini.go167
-rw-r--r--vendor/github.com/wiggin77/cfg/ini/parser.go142
-rw-r--r--vendor/github.com/wiggin77/cfg/ini/section.go109
-rw-r--r--vendor/github.com/wiggin77/cfg/listener.go11
-rw-r--r--vendor/github.com/wiggin77/cfg/nocopy.go11
-rw-r--r--vendor/github.com/wiggin77/cfg/source.go58
-rw-r--r--vendor/github.com/wiggin77/cfg/srcfile.go63
-rw-r--r--vendor/github.com/wiggin77/cfg/srcmap.go78
-rw-r--r--vendor/github.com/wiggin77/cfg/timeconv/parse.go108
-rw-r--r--vendor/github.com/wiggin77/merror/.gitignore12
-rw-r--r--vendor/github.com/wiggin77/merror/LICENSE21
-rw-r--r--vendor/github.com/wiggin77/merror/README.md2
-rw-r--r--vendor/github.com/wiggin77/merror/format.go43
-rw-r--r--vendor/github.com/wiggin77/merror/go.mod1
-rw-r--r--vendor/github.com/wiggin77/merror/merror.go87
-rw-r--r--vendor/github.com/wiggin77/srslog/.gitignore1
-rw-r--r--vendor/github.com/wiggin77/srslog/.travis.yml15
-rw-r--r--vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md50
-rw-r--r--vendor/github.com/wiggin77/srslog/LICENSE27
-rw-r--r--vendor/github.com/wiggin77/srslog/README.md147
-rw-r--r--vendor/github.com/wiggin77/srslog/constants.go68
-rw-r--r--vendor/github.com/wiggin77/srslog/dialer.go104
-rw-r--r--vendor/github.com/wiggin77/srslog/formatter.go58
-rw-r--r--vendor/github.com/wiggin77/srslog/framer.go24
-rw-r--r--vendor/github.com/wiggin77/srslog/go.mod3
-rw-r--r--vendor/github.com/wiggin77/srslog/logger.go13
-rw-r--r--vendor/github.com/wiggin77/srslog/net_conn.go76
-rw-r--r--vendor/github.com/wiggin77/srslog/srslog.go125
-rw-r--r--vendor/github.com/wiggin77/srslog/srslog_unix.go54
-rw-r--r--vendor/github.com/wiggin77/srslog/writer.go201
37 files changed, 2333 insertions, 0 deletions
diff --git a/vendor/github.com/wiggin77/cfg/.gitignore b/vendor/github.com/wiggin77/cfg/.gitignore
new file mode 100644
index 00000000..f1c181ec
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/.gitignore
@@ -0,0 +1,12 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
diff --git a/vendor/github.com/wiggin77/cfg/.travis.yml b/vendor/github.com/wiggin77/cfg/.travis.yml
new file mode 100644
index 00000000..9899b387
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/.travis.yml
@@ -0,0 +1,5 @@
+language: go
+sudo: false
+before_script:
+ - go vet ./...
+ \ No newline at end of file
diff --git a/vendor/github.com/wiggin77/cfg/LICENSE b/vendor/github.com/wiggin77/cfg/LICENSE
new file mode 100644
index 00000000..2b0bf7ef
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 wiggin77
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/wiggin77/cfg/README.md b/vendor/github.com/wiggin77/cfg/README.md
new file mode 100644
index 00000000..583a82cb
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/README.md
@@ -0,0 +1,43 @@
+# cfg
+
+[![GoDoc](https://godoc.org/github.com/wiggin77/cfg?status.svg)](https://godoc.org/github.com/wiggin77/cfg)
+[![Build Status](https://travis-ci.org/wiggin77/cfg.svg?branch=master)](https://travis-ci.org/wiggin77/cfg)
+
+Go package for app configuration. Supports chained configuration sources for multiple levels of defaults.
+Includes APIs for loading Linux style configuration files (name/value pairs) or INI files, map based properties,
+or easily create new configuration sources (e.g. load from database).
+
+Supports monitoring configuration sources for changes, hot loading properties, and notifying listeners of changes.
+
+## Usage
+
+```Go
+config := &cfg.Config{}
+defer config.Shutdown() // stops monitoring
+
+// load file via filespec string, os.File
+src, err := Config.NewSrcFileFromFilespec("./myfile.conf")
+if err != nil {
+ return err
+}
+// add src to top of chain, meaning first searched
+cfg.PrependSource(src)
+
+// fetch prop 'retries', default to 3 if not found
+val := config.Int("retries", 3)
+```
+
+See [example](./example_test.go) for more complete example, including listening for configuration changes.
+
+Config API parses the following data types:
+
+| type | method | example property values |
+| ------- | ------ | -------- |
+| string | Config.String | test, "" |
+| int | Config.Int | -1, 77, 0 |
+| int64 | Config.Int64 | -9223372036854775, 372036854775808 |
+| float64 | Config.Float64 | -77.3456, 95642331.1 |
+| bool | Config.Bool | T,t,true,True,1,0,False,false,f,F |
+| time.Duration | Config.Duration | "10ms", "2 hours", "5 min" * |
+
+\* Units of measure supported: ms, sec, min, hour, day, week, year.
diff --git a/vendor/github.com/wiggin77/cfg/config.go b/vendor/github.com/wiggin77/cfg/config.go
new file mode 100644
index 00000000..0e958102
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/config.go
@@ -0,0 +1,366 @@
+package cfg
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/wiggin77/cfg/timeconv"
+)
+
+// ErrNotFound returned when an operation is attempted on a
+// resource that doesn't exist, such as fetching a non-existing
+// property name.
+var ErrNotFound = errors.New("not found")
+
+type sourceEntry struct {
+ src Source
+ props map[string]string
+}
+
+// Config provides methods for retrieving property values from one or more
+// configuration sources.
+type Config struct {
+ mutexSrc sync.RWMutex
+ mutexListeners sync.RWMutex
+ srcs []*sourceEntry
+ chgListeners []ChangedListener
+ shutdown chan interface{}
+ wantPanicOnError bool
+}
+
+// PrependSource inserts one or more `Sources` at the beginning of
+// the list of sources such that the first source will be the
+// source checked first when resolving a property value.
+func (config *Config) PrependSource(srcs ...Source) {
+ arr := config.wrapSources(srcs...)
+
+ config.mutexSrc.Lock()
+ if config.shutdown == nil {
+ config.shutdown = make(chan interface{})
+ }
+ config.srcs = append(arr, config.srcs...)
+ config.mutexSrc.Unlock()
+
+ for _, se := range arr {
+ if _, ok := se.src.(SourceMonitored); ok {
+ config.monitor(se)
+ }
+ }
+}
+
+// AppendSource appends one or more `Sources` at the end of
+// the list of sources such that the last source will be the
+// source checked last when resolving a property value.
+func (config *Config) AppendSource(srcs ...Source) {
+ arr := config.wrapSources(srcs...)
+
+ config.mutexSrc.Lock()
+ if config.shutdown == nil {
+ config.shutdown = make(chan interface{})
+ }
+ config.srcs = append(config.srcs, arr...)
+ config.mutexSrc.Unlock()
+
+ for _, se := range arr {
+ if _, ok := se.src.(SourceMonitored); ok {
+ config.monitor(se)
+ }
+ }
+}
+
+// wrapSources wraps one or more Source's and returns
+// them as an array of `sourceEntry`.
+func (config *Config) wrapSources(srcs ...Source) []*sourceEntry {
+ arr := make([]*sourceEntry, 0, len(srcs))
+ for _, src := range srcs {
+ se := &sourceEntry{src: src}
+ config.reloadProps(se)
+ arr = append(arr, se)
+ }
+ return arr
+}
+
+// SetWantPanicOnError sets the flag determining if Config
+// should panic when `GetProps` or `GetLastModified` errors
+// for a `Source`.
+func (config *Config) SetWantPanicOnError(b bool) {
+ config.mutexSrc.Lock()
+ config.wantPanicOnError = b
+ config.mutexSrc.Unlock()
+}
+
+// ShouldPanicOnError gets the flag determining if Config
+// should panic when `GetProps` or `GetLastModified` errors
+// for a `Source`.
+func (config *Config) ShouldPanicOnError() (b bool) {
+ config.mutexSrc.RLock()
+ b = config.wantPanicOnError
+ config.mutexSrc.RUnlock()
+ return b
+}
+
+// getProp returns the value of a named property.
+// Each `Source` is checked, in the order created by adding via
+// `AppendSource` and `PrependSource`, until a value for the
+// property is found.
+func (config *Config) getProp(name string) (val string, ok bool) {
+ config.mutexSrc.RLock()
+ defer config.mutexSrc.RUnlock()
+
+ var s string
+ for _, se := range config.srcs {
+ if se.props != nil {
+ if s, ok = se.props[name]; ok {
+ val = strings.TrimSpace(s)
+ return
+ }
+ }
+ }
+ return
+}
+
+// String returns the value of the named prop as a string.
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+func (config *Config) String(name string, def string) (val string, err error) {
+ if v, ok := config.getProp(name); ok {
+ val = v
+ err = nil
+ return
+ }
+
+ err = ErrNotFound
+ val = def
+ return
+}
+
+// Int returns the value of the named prop as an `int`.
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+//
+// See config.String
+func (config *Config) Int(name string, def int) (val int, err error) {
+ var s string
+ if s, err = config.String(name, ""); err == nil {
+ var i int64
+ if i, err = strconv.ParseInt(s, 10, 32); err == nil {
+ val = int(i)
+ }
+ }
+ if err != nil {
+ val = def
+ }
+ return
+}
+
+// Int64 returns the value of the named prop as an `int64`.
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+//
+// See config.String
+func (config *Config) Int64(name string, def int64) (val int64, err error) {
+ var s string
+ if s, err = config.String(name, ""); err == nil {
+ val, err = strconv.ParseInt(s, 10, 64)
+ }
+ if err != nil {
+ val = def
+ }
+ return
+}
+
+// Float64 returns the value of the named prop as a `float64`.
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+//
+// See config.String
+func (config *Config) Float64(name string, def float64) (val float64, err error) {
+ var s string
+ if s, err = config.String(name, ""); err == nil {
+ val, err = strconv.ParseFloat(s, 64)
+ }
+ if err != nil {
+ val = def
+ }
+ return
+}
+
+// Bool returns the value of the named prop as a `bool`.
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+//
+// Supports (t, true, 1, y, yes) for true, and (f, false, 0, n, no) for false,
+// all case-insensitive.
+//
+// See config.String
+func (config *Config) Bool(name string, def bool) (val bool, err error) {
+ var s string
+ if s, err = config.String(name, ""); err == nil {
+ switch strings.ToLower(s) {
+ case "t", "true", "1", "y", "yes":
+ val = true
+ case "f", "false", "0", "n", "no":
+ val = false
+ default:
+ err = errors.New("invalid syntax")
+ }
+ }
+ if err != nil {
+ val = def
+ }
+ return
+}
+
+// Duration returns the value of the named prop as a `time.Duration`, representing
+// a span of time.
+//
+// Units of measure are supported: ms, sec, min, hour, day, week, year.
+// See config.UnitsToMillis for a complete list of units supported.
+//
+// If the property is not found then the supplied default `def`
+// and `ErrNotFound` are returned.
+//
+// See config.String
+func (config *Config) Duration(name string, def time.Duration) (val time.Duration, err error) {
+ var s string
+ if s, err = config.String(name, ""); err == nil {
+ var ms int64
+ ms, err = timeconv.ParseMilliseconds(s)
+ val = time.Duration(ms) * time.Millisecond
+ }
+ if err != nil {
+ val = def
+ }
+ return
+}
+
+// AddChangedListener adds a listener that will receive notifications
+// whenever one or more property values change within the config.
+func (config *Config) AddChangedListener(l ChangedListener) {
+ config.mutexListeners.Lock()
+ defer config.mutexListeners.Unlock()
+
+ config.chgListeners = append(config.chgListeners, l)
+}
+
+// RemoveChangedListener removes all instances of a ChangedListener.
+// Returns `ErrNotFound` if the listener was not present.
+func (config *Config) RemoveChangedListener(l ChangedListener) error {
+ config.mutexListeners.Lock()
+ defer config.mutexListeners.Unlock()
+
+ dest := make([]ChangedListener, 0, len(config.chgListeners))
+ err := ErrNotFound
+
+ // Remove all instances of the listener by
+ // copying list while filtering.
+ for _, s := range config.chgListeners {
+ if s != l {
+ dest = append(dest, s)
+ } else {
+ err = nil
+ }
+ }
+ config.chgListeners = dest
+ return err
+}
+
+// Shutdown can be called to stop monitoring of all config sources.
+func (config *Config) Shutdown() {
+ config.mutexSrc.RLock()
+ defer config.mutexSrc.RUnlock()
+ if config.shutdown != nil {
+ close(config.shutdown)
+ }
+}
+
+// onSourceChanged is called whenever one or more properties of a
+// config source has changed.
+func (config *Config) onSourceChanged(src SourceMonitored) {
+ defer func() {
+ if p := recover(); p != nil {
+ fmt.Println(p)
+ }
+ }()
+ config.mutexListeners.RLock()
+ defer config.mutexListeners.RUnlock()
+ for _, l := range config.chgListeners {
+ l.ConfigChanged(config, src)
+ }
+}
+
+// monitor periodically checks a config source for changes.
+func (config *Config) monitor(se *sourceEntry) {
+ go func(se *sourceEntry, shutdown <-chan interface{}) {
+ var src SourceMonitored
+ var ok bool
+ if src, ok = se.src.(SourceMonitored); !ok {
+ return
+ }
+ paused := false
+ last := time.Time{}
+ freq := src.GetMonitorFreq()
+ if freq <= 0 {
+ paused = true
+ freq = 10
+ last, _ = src.GetLastModified()
+ }
+ timer := time.NewTimer(freq)
+ for {
+ select {
+ case <-timer.C:
+ if !paused {
+ if latest, err := src.GetLastModified(); err != nil {
+ if config.ShouldPanicOnError() {
+ panic(fmt.Sprintf("error <%v> getting last modified for %v", err, src))
+ }
+ } else {
+ if last.Before(latest) {
+ last = latest
+ config.reloadProps(se)
+ // TODO: calc diff and provide detailed changes
+ config.onSourceChanged(src)
+ }
+ }
+ }
+ freq = src.GetMonitorFreq()
+ if freq <= 0 {
+ paused = true
+ freq = 10
+ } else {
+ paused = false
+ }
+ timer.Reset(freq)
+ case <-shutdown:
+ // stop the timer and exit
+ if !timer.Stop() {
+ <-timer.C
+ }
+ return
+ }
+ }
+ }(se, config.shutdown)
+}
+
+// reloadProps causes a Source to reload its properties.
+func (config *Config) reloadProps(se *sourceEntry) {
+ config.mutexSrc.Lock()
+ defer config.mutexSrc.Unlock()
+
+ m, err := se.src.GetProps()
+ if err != nil {
+ if config.wantPanicOnError {
+ panic(fmt.Sprintf("GetProps error for %v", se.src))
+ }
+ return
+ }
+
+ se.props = make(map[string]string)
+ for k, v := range m {
+ se.props[k] = v
+ }
+}
diff --git a/vendor/github.com/wiggin77/cfg/go.mod b/vendor/github.com/wiggin77/cfg/go.mod
new file mode 100644
index 00000000..2e5a038e
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/go.mod
@@ -0,0 +1,5 @@
+module github.com/wiggin77/cfg
+
+go 1.12
+
+require github.com/wiggin77/merror v1.0.2
diff --git a/vendor/github.com/wiggin77/cfg/go.sum b/vendor/github.com/wiggin77/cfg/go.sum
new file mode 100644
index 00000000..30fd3b58
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/go.sum
@@ -0,0 +1,2 @@
+github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
+github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=
diff --git a/vendor/github.com/wiggin77/cfg/ini/ini.go b/vendor/github.com/wiggin77/cfg/ini/ini.go
new file mode 100644
index 00000000..d28d7444
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/ini/ini.go
@@ -0,0 +1,167 @@
+package ini
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "sync"
+ "time"
+)
+
+// Ini provides parsing and querying of INI format or simple name/value pairs
+// such as a simple config file.
+// A name/value pair format is just an INI with no sections, and properties can
+// be queried using an empty section name.
+type Ini struct {
+ mutex sync.RWMutex
+ m map[string]*Section
+ lm time.Time
+}
+
+// LoadFromFilespec loads an INI file from string containing path and filename.
+func (ini *Ini) LoadFromFilespec(filespec string) error {
+ f, err := os.Open(filespec)
+ if err != nil {
+ return err
+ }
+ return ini.LoadFromFile(f)
+}
+
+// LoadFromFile loads an INI file from `os.File`.
+func (ini *Ini) LoadFromFile(file *os.File) error {
+
+ fi, err := file.Stat()
+ if err != nil {
+ return err
+ }
+ lm := fi.ModTime()
+
+ if err := ini.LoadFromReader(file); err != nil {
+ return err
+ }
+ ini.lm = lm
+ return nil
+}
+
+// LoadFromReader loads an INI file from an `io.Reader`.
+func (ini *Ini) LoadFromReader(reader io.Reader) error {
+ data, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return err
+ }
+ return ini.LoadFromString(string(data))
+}
+
+// LoadFromString parses an INI from a string .
+func (ini *Ini) LoadFromString(s string) error {
+ m, err := getSections(s)
+ if err != nil {
+ return err
+ }
+ ini.mutex.Lock()
+ ini.m = m
+ ini.lm = time.Now()
+ ini.mutex.Unlock()
+ return nil
+}
+
+// GetLastModified returns the last modified timestamp of the
+// INI contents.
+func (ini *Ini) GetLastModified() time.Time {
+ return ini.lm
+}
+
+// GetSectionNames returns the names of all sections in this INI.
+// Note, the returned section names are a snapshot in time, meaning
+// other goroutines may change the contents of this INI as soon as
+// the method returns.
+func (ini *Ini) GetSectionNames() []string {
+ ini.mutex.RLock()
+ defer ini.mutex.RUnlock()
+
+ arr := make([]string, 0, len(ini.m))
+ for key := range ini.m {
+ arr = append(arr, key)
+ }
+ return arr
+}
+
+// GetKeys returns the names of all keys in the specified section.
+// Note, the returned key names are a snapshot in time, meaning other
+// goroutines may change the contents of this INI as soon as the
+// method returns.
+func (ini *Ini) GetKeys(sectionName string) ([]string, error) {
+ sec, err := ini.getSection(sectionName)
+ if err != nil {
+ return nil, err
+ }
+ return sec.getKeys(), nil
+}
+
+// getSection returns the named section.
+func (ini *Ini) getSection(sectionName string) (*Section, error) {
+ ini.mutex.RLock()
+ defer ini.mutex.RUnlock()
+
+ sec, ok := ini.m[sectionName]
+ if !ok {
+ return nil, fmt.Errorf("section '%s' not found", sectionName)
+ }
+ return sec, nil
+}
+
+// GetFlattenedKeys returns all section names plus keys as one
+// flattened array.
+func (ini *Ini) GetFlattenedKeys() []string {
+ ini.mutex.RLock()
+ defer ini.mutex.RUnlock()
+
+ arr := make([]string, 0, len(ini.m)*2)
+ for _, section := range ini.m {
+ keys := section.getKeys()
+ for _, key := range keys {
+ name := section.GetName()
+ if name != "" {
+ key = name + "." + key
+ }
+ arr = append(arr, key)
+ }
+ }
+ return arr
+}
+
+// GetProp returns the value of the specified key in the named section.
+func (ini *Ini) GetProp(section string, key string) (val string, ok bool) {
+ sec, err := ini.getSection(section)
+ if err != nil {
+ return val, false
+ }
+ return sec.GetProp(key)
+}
+
+// ToMap returns a flattened map of the section name plus keys mapped
+// to values.
+func (ini *Ini) ToMap() map[string]string {
+ m := make(map[string]string)
+
+ ini.mutex.RLock()
+ defer ini.mutex.RUnlock()
+
+ for _, section := range ini.m {
+ for _, key := range section.getKeys() {
+ val, ok := section.GetProp(key)
+ if ok {
+ name := section.GetName()
+ var mapkey string
+ if name != "" {
+ mapkey = name + "." + key
+ } else {
+ mapkey = key
+ }
+ m[mapkey] = val
+ }
+ }
+ }
+ return m
+}
diff --git a/vendor/github.com/wiggin77/cfg/ini/parser.go b/vendor/github.com/wiggin77/cfg/ini/parser.go
new file mode 100644
index 00000000..28916409
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/ini/parser.go
@@ -0,0 +1,142 @@
+package ini
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/wiggin77/merror"
+)
+
+// LF is linefeed
+const LF byte = 0x0A
+
+// CR is carriage return
+const CR byte = 0x0D
+
+// getSections parses an INI formatted string, or string containing just name/value pairs,
+// returns map of `Section`'s.
+//
+// Any name/value pairs appearing before a section name are added to the section named
+// with an empty string (""). Also true for Linux-style config files where all props
+// are outside a named section.
+//
+// Any errors encountered are aggregated and returned, along with the partially parsed
+// sections.
+func getSections(str string) (map[string]*Section, error) {
+ merr := merror.New()
+ mapSections := make(map[string]*Section)
+ lines := buildLineArray(str)
+ section := newSection("")
+
+ for _, line := range lines {
+ name, ok := parseSection(line)
+ if ok {
+ // A section name encountered. Stop processing the current one.
+ // Don't add the current section to the map if the section name is blank
+ // and the prop map is empty.
+ nameCurr := section.GetName()
+ if nameCurr != "" || section.hasKeys() {
+ mapSections[nameCurr] = section
+ }
+ // Start processing a new section.
+ section = newSection(name)
+ } else {
+ // Parse the property and add to the current section, or ignore if comment.
+ if k, v, comment, err := parseProp(line); !comment && err == nil {
+ section.setProp(k, v)
+ } else if err != nil {
+ merr.Append(err) // aggregate errors
+ }
+ }
+
+ }
+ // If the current section is not empty, add it.
+ if section.hasKeys() {
+ mapSections[section.GetName()] = section
+ }
+ return mapSections, merr.ErrorOrNil()
+}
+
+// buildLineArray parses the given string buffer and creates a list of strings,
+// one for each line in the string buffer.
+//
+// A line is considered to be terminated by any one of a line feed ('\n'),
+// a carriage return ('\r'), or a carriage return followed immediately by a
+// linefeed.
+//
+// Lines prefixed with ';' or '#' are considered comments and skipped.
+func buildLineArray(str string) []string {
+ arr := make([]string, 0, 10)
+ str = str + "\n"
+
+ iLen := len(str)
+ iPos, iBegin := 0, 0
+ var ch byte
+
+ for iPos < iLen {
+ ch = str[iPos]
+ if ch == LF || ch == CR {
+ sub := str[iBegin:iPos]
+ sub = strings.TrimSpace(sub)
+ if sub != "" && !strings.HasPrefix(sub, ";") && !strings.HasPrefix(sub, "#") {
+ arr = append(arr, sub)
+ }
+ iPos++
+ if ch == CR && iPos < iLen && str[iPos] == LF {
+ iPos++
+ }
+ iBegin = iPos
+ } else {
+ iPos++
+ }
+ }
+ return arr
+}
+
+// parseSection parses the specified string for a section name enclosed in square brackets.
+// Returns the section name found, or `ok=false` if `str` is not a section header.
+func parseSection(str string) (name string, ok bool) {
+ str = strings.TrimSpace(str)
+ if !strings.HasPrefix(str, "[") {
+ return "", false
+ }
+ iCloser := strings.Index(str, "]")
+ if iCloser == -1 {
+ return "", false
+ }
+ return strings.TrimSpace(str[1:iCloser]), true
+}
+
+// parseProp parses the specified string and extracts a key/value pair.
+//
+// If the string is a comment (prefixed with ';' or '#') then `comment=true`
+// and key will be empty.
+func parseProp(str string) (key string, val string, comment bool, err error) {
+ iLen := len(str)
+ iEqPos := strings.Index(str, "=")
+ if iEqPos == -1 {
+ return "", "", false, fmt.Errorf("not a key/value pair:'%s'", str)
+ }
+
+ key = str[0:iEqPos]
+ key = strings.TrimSpace(key)
+ if iEqPos+1 < iLen {
+ val = str[iEqPos+1:]
+ val = strings.TrimSpace(val)
+ }
+
+ // Check that the key has at least 1 char.
+ if key == "" {
+ return "", "", false, fmt.Errorf("key is empty for '%s'", str)
+ }
+
+ // Check if this line is a comment that just happens
+ // to have an equals sign in it. Not an error, but not a
+ // useable line either.
+ if strings.HasPrefix(key, ";") || strings.HasPrefix(key, "#") {
+ key = ""
+ val = ""
+ comment = true
+ }
+ return key, val, comment, err
+}
diff --git a/vendor/github.com/wiggin77/cfg/ini/section.go b/vendor/github.com/wiggin77/cfg/ini/section.go
new file mode 100644
index 00000000..18c4c254
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/ini/section.go
@@ -0,0 +1,109 @@
+package ini
+
+import (
+ "fmt"
+ "strings"
+ "sync"
+)
+
+// Section represents a section in an INI file. The section has a name, which is
+// enclosed in square brackets in the file. The section also has an array of
+// key/value pairs.
+type Section struct {
+ name string
+ props map[string]string
+ mtx sync.RWMutex
+}
+
+func newSection(name string) *Section {
+ sec := &Section{}
+ sec.name = name
+ sec.props = make(map[string]string)
+ return sec
+}
+
+// addLines addes an array of strings containing name/value pairs
+// of the format `key=value`.
+//func addLines(lines []string) {
+// TODO
+//}
+
+// GetName returns the name of the section.
+func (sec *Section) GetName() (name string) {
+ sec.mtx.RLock()
+ name = sec.name
+ sec.mtx.RUnlock()
+ return
+}
+
+// GetProp returns the value associated with the given key, or
+// `ok=false` if key does not exist.
+func (sec *Section) GetProp(key string) (val string, ok bool) {
+ sec.mtx.RLock()
+ val, ok = sec.props[key]
+ sec.mtx.RUnlock()
+ return
+}
+
+// SetProp sets the value associated with the given key.
+func (sec *Section) setProp(key string, val string) {
+ sec.mtx.Lock()
+ sec.props[key] = val
+ sec.mtx.Unlock()
+}
+
+// hasKeys returns true if there are one or more properties in
+// this section.
+func (sec *Section) hasKeys() (b bool) {
+ sec.mtx.RLock()
+ b = len(sec.props) > 0
+ sec.mtx.RUnlock()
+ return
+}
+
+// getKeys returns an array containing all keys in this section.
+func (sec *Section) getKeys() []string {
+ sec.mtx.RLock()
+ defer sec.mtx.RUnlock()
+
+ arr := make([]string, len(sec.props))
+ idx := 0
+ for k := range sec.props {
+ arr[idx] = k
+ idx++
+ }
+ return arr
+}
+
+// combine the given section with this one.
+func (sec *Section) combine(sec2 *Section) {
+ sec.mtx.Lock()
+ sec2.mtx.RLock()
+ defer sec.mtx.Unlock()
+ defer sec2.mtx.RUnlock()
+
+ for k, v := range sec2.props {
+ sec.props[k] = v
+ }
+}
+
+// String returns a string representation of this section.
+func (sec *Section) String() string {
+ return fmt.Sprintf("[%s]\n%s", sec.GetName(), sec.StringPropsOnly())
+}
+
+// StringPropsOnly returns a string representation of this section
+// without the section header.
+func (sec *Section) StringPropsOnly() string {
+ sec.mtx.RLock()
+ defer sec.mtx.RUnlock()
+ sb := &strings.Builder{}
+
+ for k, v := range sec.props {
+ sb.WriteString(k)
+ sb.WriteString("=")
+ sb.WriteString(v)
+ sb.WriteString("\n")
+ }
+ return sb.String()
+}
diff --git a/vendor/github.com/wiggin77/cfg/listener.go b/vendor/github.com/wiggin77/cfg/listener.go
new file mode 100644
index 00000000..12ea4e45
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/listener.go
@@ -0,0 +1,11 @@
+package cfg
+
+// ChangedListener interface is for receiving notifications
+// when one or more properties within monitored config sources
+// (SourceMonitored) have changed values.
+type ChangedListener interface {
+
+ // Changed is called when one or more properties in a `SourceMonitored` has a
+ // changed value.
+ ConfigChanged(cfg *Config, src SourceMonitored)
+}
diff --git a/vendor/github.com/wiggin77/cfg/nocopy.go b/vendor/github.com/wiggin77/cfg/nocopy.go
new file mode 100644
index 00000000..f2450c0b
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/nocopy.go
@@ -0,0 +1,11 @@
+package cfg
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://golang.org/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
diff --git a/vendor/github.com/wiggin77/cfg/source.go b/vendor/github.com/wiggin77/cfg/source.go
new file mode 100644
index 00000000..09083e97
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/source.go
@@ -0,0 +1,58 @@
+package cfg
+
+import (
+ "sync"
+ "time"
+)
+
+// Source is the interface required for any source of name/value pairs.
+type Source interface {
+
+ // GetProps fetches all the properties from a source and returns
+ // them as a map.
+ GetProps() (map[string]string, error)
+}
+
+// SourceMonitored is the interface required for any config source that is
+// monitored for changes.
+type SourceMonitored interface {
+ Source
+
+ // GetLastModified returns the time of the latest modification to any
+ // property value within the source. If a source does not support
+ // modifying properties at runtime then the zero value for `Time`
+ // should be returned to ensure reload events are not generated.
+ GetLastModified() (time.Time, error)
+
+ // GetMonitorFreq returns the frequency as a `time.Duration` between
+ // checks for changes to this config source.
+ //
+ // Returning zero (or less) will temporarily suspend calls to `GetLastModified`
+ // and `GetMonitorFreq` will be called every 10 seconds until resumed, after which
+ // `GetMontitorFreq` will be called at a frequency roughly equal to the `time.Duration`
+ // returned.
+ GetMonitorFreq() time.Duration
+}
+
+// AbstractSourceMonitor can be embedded in a custom `Source` to provide the
+// basic plumbing for monitor frequency.
+type AbstractSourceMonitor struct {
+ mutex sync.RWMutex
+ freq time.Duration
+}
+
+// GetMonitorFreq returns the frequency as a `time.Duration` between
+// checks for changes to this config source.
+func (asm *AbstractSourceMonitor) GetMonitorFreq() (freq time.Duration) {
+ asm.mutex.RLock()
+ freq = asm.freq
+ asm.mutex.RUnlock()
+ return
+}
+
+// SetMonitorFreq sets the frequency between checks for changes to this config source.
+func (asm *AbstractSourceMonitor) SetMonitorFreq(freq time.Duration) {
+ asm.mutex.Lock()
+ asm.freq = freq
+ asm.mutex.Unlock()
+}
diff --git a/vendor/github.com/wiggin77/cfg/srcfile.go b/vendor/github.com/wiggin77/cfg/srcfile.go
new file mode 100644
index 00000000..f42c69fa
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/srcfile.go
@@ -0,0 +1,63 @@
+package cfg
+
+import (
+ "os"
+ "time"
+
+ "github.com/wiggin77/cfg/ini"
+)
+
+// SrcFile is a configuration `Source` backed by a file containing
+// name/value pairs or INI format.
+type SrcFile struct {
+ AbstractSourceMonitor
+ ini ini.Ini
+ file *os.File
+}
+
+// NewSrcFileFromFilespec creates a new SrcFile with the specified filespec.
+func NewSrcFileFromFilespec(filespec string) (*SrcFile, error) {
+ file, err := os.Open(filespec)
+ if err != nil {
+ return nil, err
+ }
+ return NewSrcFile(file)
+}
+
+// NewSrcFile creates a new SrcFile with the specified os.File.
+func NewSrcFile(file *os.File) (*SrcFile, error) {
+ sf := &SrcFile{}
+ sf.freq = time.Minute
+ sf.file = file
+ if err := sf.ini.LoadFromFile(file); err != nil {
+ return nil, err
+ }
+ return sf, nil
+}
+
+// GetProps fetches all the properties from a source and returns
+// them as a map.
+func (sf *SrcFile) GetProps() (map[string]string, error) {
+ lm, err := sf.GetLastModified()
+ if err != nil {
+ return nil, err
+ }
+
+ // Check if we need to reload.
+ if sf.ini.GetLastModified() != lm {
+ if err := sf.ini.LoadFromFile(sf.file); err != nil {
+ return nil, err
+ }
+ }
+ return sf.ini.ToMap(), nil
+}
+
+// GetLastModified returns the time of the latest modification to any
+// property value within the source.
+func (sf *SrcFile) GetLastModified() (time.Time, error) {
+ fi, err := sf.file.Stat()
+ if err != nil {
+ return time.Now(), err
+ }
+ return fi.ModTime(), nil
+}
diff --git a/vendor/github.com/wiggin77/cfg/srcmap.go b/vendor/github.com/wiggin77/cfg/srcmap.go
new file mode 100644
index 00000000..321db27a
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/srcmap.go
@@ -0,0 +1,78 @@
+package cfg
+
+import (
+ "time"
+)
+
+// SrcMap is a configuration `Source` backed by a simple map.
+type SrcMap struct {
+ AbstractSourceMonitor
+ m map[string]string
+ lm time.Time
+}
+
+// NewSrcMap creates an empty `SrcMap`.
+func NewSrcMap() *SrcMap {
+ sm := &SrcMap{}
+ sm.m = make(map[string]string)
+ sm.lm = time.Now()
+ sm.freq = time.Minute
+ return sm
+}
+
+// NewSrcMapFromMap creates a `SrcMap` containing a copy of the
+// specified map.
+func NewSrcMapFromMap(mapIn map[string]string) *SrcMap {
+ sm := NewSrcMap()
+ sm.PutAll(mapIn)
+ return sm
+}
+
+// Put inserts or updates a value in the `SrcMap`.
+func (sm *SrcMap) Put(key string, val string) {
+ sm.mutex.Lock()
+ sm.m[key] = val
+ sm.lm = time.Now()
+ sm.mutex.Unlock()
+}
+
+// PutAll inserts a copy of `mapIn` into the `SrcMap`
+func (sm *SrcMap) PutAll(mapIn map[string]string) {
+ sm.mutex.Lock()
+ defer sm.mutex.Unlock()
+
+ for k, v := range mapIn {
+ sm.m[k] = v
+ }
+ sm.lm = time.Now()
+}
+
+// GetProps fetches all the properties from a source and returns
+// them as a map.
+func (sm *SrcMap) GetProps() (m map[string]string, err error) {
+ sm.mutex.RLock()
+ m = sm.m
+ sm.mutex.RUnlock()
+ return
+}
+
+// GetLastModified returns the time of the latest modification to any
+// property value within the source. If a source does not support
+// modifying properties at runtime then the zero value for `Time`
+// should be returned to ensure reload events are not generated.
+func (sm *SrcMap) GetLastModified() (last time.Time, err error) {
+ sm.mutex.RLock()
+ last = sm.lm
+ sm.mutex.RUnlock()
+ return
+}
+
+// GetMonitorFreq returns the frequency as a `time.Duration` between
+// checks for changes to this config source. Defaults to 1 minute
+// unless changed with `SetMonitorFreq`.
+func (sm *SrcMap) GetMonitorFreq() (freq time.Duration) {
+ sm.mutex.RLock()
+ freq = sm.freq
+ sm.mutex.RUnlock()
+ return
+}
diff --git a/vendor/github.com/wiggin77/cfg/timeconv/parse.go b/vendor/github.com/wiggin77/cfg/timeconv/parse.go
new file mode 100644
index 00000000..218ef43a
--- /dev/null
+++ b/vendor/github.com/wiggin77/cfg/timeconv/parse.go
@@ -0,0 +1,108 @@
+package timeconv
+
+import (
+ "fmt"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// MillisPerSecond is the number of millseconds per second.
+const MillisPerSecond int64 = 1000
+
+// MillisPerMinute is the number of millseconds per minute.
+const MillisPerMinute int64 = MillisPerSecond * 60
+
+// MillisPerHour is the number of millseconds per hour.
+const MillisPerHour int64 = MillisPerMinute * 60
+
+// MillisPerDay is the number of millseconds per day.
+const MillisPerDay int64 = MillisPerHour * 24
+
+// MillisPerWeek is the number of millseconds per week.
+const MillisPerWeek int64 = MillisPerDay * 7
+
+// MillisPerYear is the approximate number of millseconds per year.
+const MillisPerYear int64 = MillisPerDay*365 + int64((float64(MillisPerDay) * 0.25))
+
+// ParseMilliseconds parses a string containing a number plus
+// a unit of measure for time and returns the number of milliseconds
+// it represents.
+//
+// Example:
+// * "1 second" returns 1000
+// * "1 minute" returns 60000
+// * "1 hour" returns 3600000
+//
+// See config.UnitsToMillis for a list of supported units of measure.
+func ParseMilliseconds(str string) (int64, error) {
+ s := strings.TrimSpace(str)
+ reg := regexp.MustCompile("([0-9\\.\\-+]*)(.*)")
+ matches := reg.FindStringSubmatch(s)
+ if matches == nil || len(matches) < 1 || matches[1] == "" {
+ return 0, fmt.Errorf("invalid syntax - '%s'", s)
+ }
+ digits := matches[1]
+ units := "ms"
+ if len(matches) > 1 && matches[2] != "" {
+ units = matches[2]
+ }
+
+ fDigits, err := strconv.ParseFloat(digits, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ msPerUnit, err := UnitsToMillis(units)
+ if err != nil {
+ return 0, err
+ }
+
+ // Check for overflow.
+ fms := float64(msPerUnit) * fDigits
+ if fms > math.MaxInt64 || fms < math.MinInt64 {
+ return 0, fmt.Errorf("out of range - '%s' overflows", s)
+ }
+ ms := int64(fms)
+ return ms, nil
+}
+
+// UnitsToMillis returns the number of milliseconds represented by the specified unit of measure.
+//
+// Example:
+// * "second" returns 1000 <br/>
+// * "minute" returns 60000 <br/>
+// * "hour" returns 3600000 <br/>
+//
+// Supported units of measure:
+// * "milliseconds", "millis", "ms", "millisecond"
+// * "seconds", "sec", "s", "second"
+// * "minutes", "mins", "min", "m", "minute"
+// * "hours", "h", "hour"
+// * "days", "d", "day"
+// * "weeks", "w", "week"
+// * "years", "y", "year"
+func UnitsToMillis(units string) (ms int64, err error) {
+ u := strings.TrimSpace(units)
+ u = strings.ToLower(u)
+ switch u {
+ case "milliseconds", "millisecond", "millis", "ms":
+ ms = 1
+ case "seconds", "second", "sec", "s":
+ ms = MillisPerSecond
+ case "minutes", "minute", "mins", "min", "m":
+ ms = MillisPerMinute
+ case "hours", "hour", "h":
+ ms = MillisPerHour
+ case "days", "day", "d":
+ ms = MillisPerDay
+ case "weeks", "week", "w":
+ ms = MillisPerWeek
+ case "years", "year", "y":
+ ms = MillisPerYear
+ default:
+ err = fmt.Errorf("invalid syntax - '%s' not a supported unit of measure", u)
+ }
+ return
+}
diff --git a/vendor/github.com/wiggin77/merror/.gitignore b/vendor/github.com/wiggin77/merror/.gitignore
new file mode 100644
index 00000000..f1c181ec
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/.gitignore
@@ -0,0 +1,12 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
diff --git a/vendor/github.com/wiggin77/merror/LICENSE b/vendor/github.com/wiggin77/merror/LICENSE
new file mode 100644
index 00000000..2b0bf7ef
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 wiggin77
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/wiggin77/merror/README.md b/vendor/github.com/wiggin77/merror/README.md
new file mode 100644
index 00000000..8a31687f
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/README.md
@@ -0,0 +1,2 @@
+# merror
+Multiple Error aggregator for Golang.
diff --git a/vendor/github.com/wiggin77/merror/format.go b/vendor/github.com/wiggin77/merror/format.go
new file mode 100644
index 00000000..8ba9aa82
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/format.go
@@ -0,0 +1,43 @@
+package merror
+
+import (
+ "fmt"
+ "strings"
+)
+
+// FormatterFunc is a function that converts a merror
+// to a string.
+type FormatterFunc func(merr *MError) string
+
+// GlobalFormatter is the global merror formatter.
+// Set this to a custom formatter if desired.
+var GlobalFormatter = defaultFormatter
+
+// defaultFormatter
+func defaultFormatter(merr *MError) string {
+ count := 0
+ overflow := 0
+
+ var format func(sb *strings.Builder, merr *MError, indent string)
+ format = func(sb *strings.Builder, merr *MError, indent string) {
+ count += merr.Len()
+ overflow += merr.Overflow()
+
+ fmt.Fprintf(sb, "%sMError:\n", indent)
+ for _, err := range merr.Errors() {
+ if e, ok := err.(*MError); ok {
+ format(sb, e, indent+" ")
+ } else {
+ fmt.Fprintf(sb, "%s%s\n", indent, err.Error())
+ }
+ }
+ }
+
+ sb := &strings.Builder{}
+ format(sb, merr, "")
+ fmt.Fprintf(sb, "%d errors total.\n", count)
+ if merr.overflow > 0 {
+ fmt.Fprintf(sb, "%d errors truncated.\n", overflow)
+ }
+ return sb.String()
+}
diff --git a/vendor/github.com/wiggin77/merror/go.mod b/vendor/github.com/wiggin77/merror/go.mod
new file mode 100644
index 00000000..44982f78
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/go.mod
@@ -0,0 +1 @@
+module github.com/wiggin77/merror
diff --git a/vendor/github.com/wiggin77/merror/merror.go b/vendor/github.com/wiggin77/merror/merror.go
new file mode 100644
index 00000000..01f19913
--- /dev/null
+++ b/vendor/github.com/wiggin77/merror/merror.go
@@ -0,0 +1,87 @@
+package merror
+
+// MError represents zero or more errors that can be
+// accumulated via the `Append` method.
+type MError struct {
+ cap int
+ errors []error
+ overflow int
+ formatter FormatterFunc
+}
+
+// New returns a new instance of `MError` with no limit on the
+// number of errors that can be appended.
+func New() *MError {
+ me := &MError{}
+ me.errors = make([]error, 0, 10)
+ return me
+}
+
+// NewWithCap returns a new instance of `MError` with a maximum
+// capacity of `cap` errors. If exceeded only the overflow counter
+// will be incremented.
+//
+// A `cap` of zero of less means no cap and max size of a slice
+// on the current platform is the upper bound.
+func NewWithCap(cap int) *MError {
+ me := New()
+ me.cap = cap
+ return me
+}
+
+// Append adds an error to the aggregated error list.
+func (me *MError) Append(err error) {
+ if err == nil {
+ return
+ }
+ if me.cap > 0 && len(me.errors) >= me.cap {
+ me.overflow++
+ } else {
+ me.errors = append(me.errors, err)
+ }
+}
+
+// Errors returns an array of the `error` instances that have been
+// appended to this `MError`.
+func (me *MError) Errors() []error {
+ return me.errors
+}
+
+// Len returns the number of errors that have been appended.
+func (me *MError) Len() int {
+ return len(me.errors)
+}
+
+// Overflow returns the number of errors that have been truncated
+// because maximum capacity was exceeded.
+func (me *MError) Overflow() int {
+ return me.overflow
+}
+
+// SetFormatter sets the `FormatterFunc` to be used when `Error` is
+// called. The previous `FormatterFunc` is returned.
+func (me *MError) SetFormatter(f FormatterFunc) (old FormatterFunc) {
+ old = me.formatter
+ me.formatter = f
+ return
+}
+
+// ErrorOrNil returns nil if this `MError` contains no errors,
+// otherwise this `MError` is returned.
+func (me *MError) ErrorOrNil() error {
+ if me == nil || len(me.errors) == 0 {
+ return nil
+ }
+ return me
+}
+
+// Error returns a string representation of this MError.
+// The output format depends on the `Formatter` set for this
+// merror instance, or the global formatter if none set.
+func (me *MError) Error() string {
+ f := me.formatter
+ if f == nil {
+ f = GlobalFormatter
+ }
+ return f(me)
+}
diff --git a/vendor/github.com/wiggin77/srslog/.gitignore b/vendor/github.com/wiggin77/srslog/.gitignore
new file mode 100644
index 00000000..ebf0f2e4
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/.gitignore
@@ -0,0 +1 @@
+.cover
diff --git a/vendor/github.com/wiggin77/srslog/.travis.yml b/vendor/github.com/wiggin77/srslog/.travis.yml
new file mode 100644
index 00000000..921150e9
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/.travis.yml
@@ -0,0 +1,15 @@
+sudo: required
+dist: trusty
+group: edge
+language: go
+go:
+- 1.5
+before_install:
+ - pip install --user codecov
+script:
+- |
+ go get ./...
+ go test -v -coverprofile=coverage.txt -covermode=atomic
+ go vet
+after_success:
+ - codecov
diff --git a/vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md b/vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..18ac49fc
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md
@@ -0,0 +1,50 @@
+# 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/
diff --git a/vendor/github.com/wiggin77/srslog/LICENSE b/vendor/github.com/wiggin77/srslog/LICENSE
new file mode 100644
index 00000000..9269338f
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/LICENSE
@@ -0,0 +1,27 @@
+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.
diff --git a/vendor/github.com/wiggin77/srslog/README.md b/vendor/github.com/wiggin77/srslog/README.md
new file mode 100644
index 00000000..dcacc348
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/README.md
@@ -0,0 +1,147 @@
+[![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"))
+```
+
+If you need further control over connection attempts, you can use the DialWithCustomDialer
+function. To continue with the DialWithTLSConfig example:
+
+```
+netDialer := &net.Dialer{Timeout: time.Second*5} // easy timeouts
+realNetwork := "tcp" // real network, other vars your dail func can close over
+dial := func(network, addr string) (net.Conn, error) {
+ // cannot use "network" here as it'll simply be "custom" which will fail
+ return tls.DialWithDialer(netDialer, realNetwork, addr, &config)
+}
+
+w, err := DialWithCustomDialer("custom", "192.168.0.52:514", syslog.LOG_ERR, "testtag", dial)
+```
+
+Your custom dial func can set timeouts, proxy connections, and do whatever else it needs before returning a net.Conn.
+
+# 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.
diff --git a/vendor/github.com/wiggin77/srslog/constants.go b/vendor/github.com/wiggin77/srslog/constants.go
new file mode 100644
index 00000000..600801ee
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/constants.go
@@ -0,0 +1,68 @@
+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
+ }
+}
diff --git a/vendor/github.com/wiggin77/srslog/dialer.go b/vendor/github.com/wiggin77/srslog/dialer.go
new file mode 100644
index 00000000..1ecf29b2
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/dialer.go
@@ -0,0 +1,104 @@
+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},
+ "custom": dialerFunctionWrapper{"customDialer", w.customDialer},
+ }
+ 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 = newNetConn(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 = newNetConn(c)
+ if hostname == "" {
+ hostname = c.LocalAddr().String()
+ }
+ }
+ return sc, hostname, err
+}
+
+// customDialer uses the custom dialer when the Writer was created
+// giving developers total control over how connections are made and returned.
+// Note it does not check if cdialer is nil, as it should only be referenced from getDialer.
+func (w *Writer) customDialer() (serverConn, string, error) {
+ c, err := w.customDial(w.network, w.raddr)
+ var sc serverConn
+ hostname := w.hostname
+ if err == nil {
+ sc = newNetConn(c)
+ if hostname == "" {
+ hostname = c.LocalAddr().String()
+ }
+ }
+ return sc, hostname, err
+}
diff --git a/vendor/github.com/wiggin77/srslog/formatter.go b/vendor/github.com/wiggin77/srslog/formatter.go
new file mode 100644
index 00000000..e306fd67
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/formatter.go
@@ -0,0 +1,58 @@
+package srslog
+
+import (
+ "fmt"
+ "os"
+ "time"
+)
+
+const appNameMaxLength = 48 // limit to 48 chars as per RFC5424
+
+// 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
+}
+
+// if string's length is greater than max, then use the last part
+func truncateStartStr(s string, max int) string {
+ if (len(s) > max) {
+ return s[len(s) - max:]
+ }
+ return s
+}
+
+// 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 := truncateStartStr(os.Args[0], appNameMaxLength)
+ msg := fmt.Sprintf("<%d>%d %s %s %s %d %s - %s",
+ p, 1, timestamp, hostname, appName, pid, tag, content)
+ return msg
+}
diff --git a/vendor/github.com/wiggin77/srslog/framer.go b/vendor/github.com/wiggin77/srslog/framer.go
new file mode 100644
index 00000000..ab46f0de
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/framer.go
@@ -0,0 +1,24 @@
+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)
+}
diff --git a/vendor/github.com/wiggin77/srslog/go.mod b/vendor/github.com/wiggin77/srslog/go.mod
new file mode 100644
index 00000000..393b0761
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/go.mod
@@ -0,0 +1,3 @@
+module github.com/wiggin77/srslog
+
+go 1.14
diff --git a/vendor/github.com/wiggin77/srslog/logger.go b/vendor/github.com/wiggin77/srslog/logger.go
new file mode 100644
index 00000000..3a738565
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/logger.go
@@ -0,0 +1,13 @@
+package srslog
+
+import (
+ "io/ioutil"
+ "log"
+)
+
+var Logger log.Logger
+
+func init() {
+ Logger = log.Logger{}
+ Logger.SetOutput(ioutil.Discard)
+}
diff --git a/vendor/github.com/wiggin77/srslog/net_conn.go b/vendor/github.com/wiggin77/srslog/net_conn.go
new file mode 100644
index 00000000..f3cfeb60
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/net_conn.go
@@ -0,0 +1,76 @@
+package srslog
+
+import (
+ "io"
+ "net"
+ "time"
+)
+
+// 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
+ done chan interface{}
+}
+
+// newNetConn creates a netConn instance that is monitored for unexpected socket closure.
+func newNetConn(conn net.Conn) *netConn {
+ nc := &netConn{conn: conn, done: make(chan interface{})}
+ go monitor(nc.conn, nc.done)
+ return nc
+}
+
+// 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 {
+ // signal monitor goroutine to exit
+ close(n.done)
+ // wake up monitor blocked on read (close usually is enough)
+ _ = n.conn.SetReadDeadline(time.Now())
+ // close the connection
+ return n.conn.Close()
+}
+
+// monitor continuously tries to read from the connection to detect socket close.
+// This is needed because syslog server uses a write only socket and Linux systems
+// take a long time to detect a loss of connectivity on a socket when only writing;
+// the writes simply fail without an error returned.
+func monitor(conn net.Conn, done chan interface{}) {
+ defer Logger.Println("monitor exit")
+
+ buf := make([]byte, 1)
+ for {
+ Logger.Println("monitor loop")
+
+ select {
+ case <-done:
+ return
+ case <-time.After(1 * time.Second):
+ }
+
+ err := conn.SetReadDeadline(time.Now().Add(time.Second * 30))
+ if err != nil {
+ continue
+ }
+
+ _, err = conn.Read(buf)
+ Logger.Println("monitor -- ", err)
+ if err == io.EOF {
+ Logger.Println("monitor close conn")
+ conn.Close()
+ }
+ }
+}
diff --git a/vendor/github.com/wiggin77/srslog/srslog.go b/vendor/github.com/wiggin77/srslog/srslog.go
new file mode 100644
index 00000000..b47ad72d
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/srslog.go
@@ -0,0 +1,125 @@
+package srslog
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "io/ioutil"
+ "log"
+ "net"
+ "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
+}
+
+// DialFunc is the function signature to be used for a custom dialer callback
+// with DialWithCustomDialer
+type DialFunc func(string, string) (net.Conn, 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)
+}
+
+// ErrNilDialFunc is returned from DialWithCustomDialer when a nil DialFunc is passed,
+// avoiding a nil pointer deference panic.
+var ErrNilDialFunc = errors.New("srslog: nil DialFunc passed to DialWithCustomDialer")
+
+// DialWithCustomDialer establishes a connection by calling customDial.
+// Each write to the returned Writer sends a log message with the given facility, severity and tag.
+// Network must be "custom" in order for this package to use customDial.
+// While network and raddr will be passed to customDial, it is allowed for customDial to ignore them.
+// If customDial is nil, this function returns ErrNilDialFunc.
+func DialWithCustomDialer(network, raddr string, priority Priority, tag string, customDial DialFunc) (*Writer, error) {
+ if customDial == nil {
+ return nil, ErrNilDialFunc
+ }
+ return dialAllParameters(network, raddr, priority, tag, nil, customDial)
+}
+
+// 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) {
+ return dialAllParameters(network, raddr, priority, tag, tlsConfig, nil)
+}
+
+// implementation of the various functions above
+func dialAllParameters(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config, customDial DialFunc) (*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,
+ customDial: customDial,
+ }
+
+ _, 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
+}
diff --git a/vendor/github.com/wiggin77/srslog/srslog_unix.go b/vendor/github.com/wiggin77/srslog/srslog_unix.go
new file mode 100644
index 00000000..a04d9396
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/srslog_unix.go
@@ -0,0 +1,54 @@
+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()
+}
diff --git a/vendor/github.com/wiggin77/srslog/writer.go b/vendor/github.com/wiggin77/srslog/writer.go
new file mode 100644
index 00000000..86bccba1
--- /dev/null
+++ b/vendor/github.com/wiggin77/srslog/writer.go
@@ -0,0 +1,201 @@
+package srslog
+
+import (
+ "crypto/tls"
+ "strings"
+ "sync"
+)
+
+// A Writer is a connection to a syslog server.
+type Writer struct {
+ priority Priority
+ tag string
+ hostname string
+ network string
+ raddr string
+ tlsConfig *tls.Config
+ framer Framer
+ formatter Formatter
+
+ //non-nil if custom dialer set, used in getDialer
+ customDial DialFunc
+
+ mu sync.RWMutex // guards conn
+ conn serverConn
+}
+
+// getConn provides access to the internal conn, protected by a mutex. The
+// conn is threadsafe, so it can be used while unlocked, but we want to avoid
+// race conditions on grabbing a reference to it.
+func (w *Writer) getConn() serverConn {
+ w.mu.RLock()
+ conn := w.conn
+ w.mu.RUnlock()
+ return conn
+}
+
+// setConn updates the internal conn, protected by a mutex.
+func (w *Writer) setConn(c serverConn) {
+ w.mu.Lock()
+ w.conn = c
+ w.mu.Unlock()
+}
+
+// connect makes a connection to the syslog server.
+func (w *Writer) connect() (serverConn, error) {
+ conn := w.getConn()
+ if conn != nil {
+ // ignore err from close, it makes sense to continue anyway
+ conn.close()
+ w.setConn(nil)
+ }
+
+ var hostname string
+ var err error
+ dialer := w.getDialer()
+ conn, hostname, err = dialer.Call()
+ if err == nil {
+ w.setConn(conn)
+ w.hostname = hostname
+
+ return conn, nil
+ } else {
+ return nil, err
+ }
+}
+
+// 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
+}
+
+// SetHostname changes the hostname for syslog messages if needed.
+func (w *Writer) SetHostname(hostname string) {
+ w.hostname = hostname
+}
+
+// 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))
+}
+
+// WriteWithPriority sends a log message with a custom priority.
+func (w *Writer) WriteWithPriority(p Priority, b []byte) (int, error) {
+ return w.writeAndRetryWithPriority(p, string(b))
+}
+
+// Close closes a connection to the syslog daemon.
+func (w *Writer) Close() error {
+ conn := w.getConn()
+ if conn != nil {
+ err := conn.close()
+ w.setConn(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
+}
+
+// writeAndRetry takes a severity and the string to write. Any facility passed to
+// it as part of the severity Priority will be ignored.
+func (w *Writer) writeAndRetry(severity Priority, s string) (int, error) {
+ pr := (w.priority & facilityMask) | (severity & severityMask)
+
+ return w.writeAndRetryWithPriority(pr, s)
+}
+
+// writeAndRetryWithPriority differs from writeAndRetry in that it allows setting
+// of both the facility and the severity.
+func (w *Writer) writeAndRetryWithPriority(p Priority, s string) (int, error) {
+ conn := w.getConn()
+ if conn != nil {
+ if n, err := w.write(conn, p, s); err == nil {
+ return n, err
+ }
+ }
+
+ var err error
+ if conn, err = w.connect(); err != nil {
+ return 0, err
+ }
+ return w.write(conn, p, s)
+}
+
+// write generates and writes a syslog formatted string. It formats the
+// message based on the current Formatter and Framer.
+func (w *Writer) write(conn serverConn, p Priority, msg string) (int, error) {
+ // ensure it ends in a \n
+ if !strings.HasSuffix(msg, "\n") {
+ msg += "\n"
+ }
+
+ err := 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
+}