mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-07-03 06:07:45 +00:00
Update vendor (#1265)
This commit is contained in:
12
vendor/github.com/wiggin77/cfg/.gitignore
generated
vendored
Normal file
12
vendor/github.com/wiggin77/cfg/.gitignore
generated
vendored
Normal file
@ -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
|
5
vendor/github.com/wiggin77/cfg/.travis.yml
generated
vendored
Normal file
5
vendor/github.com/wiggin77/cfg/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
language: go
|
||||
sudo: false
|
||||
before_script:
|
||||
- go vet ./...
|
||||
|
21
vendor/github.com/wiggin77/cfg/LICENSE
generated
vendored
Normal file
21
vendor/github.com/wiggin77/cfg/LICENSE
generated
vendored
Normal file
@ -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.
|
43
vendor/github.com/wiggin77/cfg/README.md
generated
vendored
Normal file
43
vendor/github.com/wiggin77/cfg/README.md
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# cfg
|
||||
|
||||
[](https://godoc.org/github.com/wiggin77/cfg)
|
||||
[](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.
|
366
vendor/github.com/wiggin77/cfg/config.go
generated
vendored
Normal file
366
vendor/github.com/wiggin77/cfg/config.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
5
vendor/github.com/wiggin77/cfg/go.mod
generated
vendored
Normal file
5
vendor/github.com/wiggin77/cfg/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
module github.com/wiggin77/cfg
|
||||
|
||||
go 1.12
|
||||
|
||||
require github.com/wiggin77/merror v1.0.2
|
2
vendor/github.com/wiggin77/cfg/go.sum
generated
vendored
Normal file
2
vendor/github.com/wiggin77/cfg/go.sum
generated
vendored
Normal file
@ -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=
|
167
vendor/github.com/wiggin77/cfg/ini/ini.go
generated
vendored
Normal file
167
vendor/github.com/wiggin77/cfg/ini/ini.go
generated
vendored
Normal file
@ -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
|
||||
}
|
142
vendor/github.com/wiggin77/cfg/ini/parser.go
generated
vendored
Normal file
142
vendor/github.com/wiggin77/cfg/ini/parser.go
generated
vendored
Normal file
@ -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
|
||||
}
|
109
vendor/github.com/wiggin77/cfg/ini/section.go
generated
vendored
Normal file
109
vendor/github.com/wiggin77/cfg/ini/section.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
11
vendor/github.com/wiggin77/cfg/listener.go
generated
vendored
Normal file
11
vendor/github.com/wiggin77/cfg/listener.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
11
vendor/github.com/wiggin77/cfg/nocopy.go
generated
vendored
Normal file
11
vendor/github.com/wiggin77/cfg/nocopy.go
generated
vendored
Normal file
@ -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() {}
|
58
vendor/github.com/wiggin77/cfg/source.go
generated
vendored
Normal file
58
vendor/github.com/wiggin77/cfg/source.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
63
vendor/github.com/wiggin77/cfg/srcfile.go
generated
vendored
Normal file
63
vendor/github.com/wiggin77/cfg/srcfile.go
generated
vendored
Normal file
@ -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
|
||||
}
|
78
vendor/github.com/wiggin77/cfg/srcmap.go
generated
vendored
Normal file
78
vendor/github.com/wiggin77/cfg/srcmap.go
generated
vendored
Normal file
@ -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
|
||||
}
|
108
vendor/github.com/wiggin77/cfg/timeconv/parse.go
generated
vendored
Normal file
108
vendor/github.com/wiggin77/cfg/timeconv/parse.go
generated
vendored
Normal file
@ -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
|
||||
}
|
12
vendor/github.com/wiggin77/merror/.gitignore
generated
vendored
Normal file
12
vendor/github.com/wiggin77/merror/.gitignore
generated
vendored
Normal file
@ -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
|
21
vendor/github.com/wiggin77/merror/LICENSE
generated
vendored
Normal file
21
vendor/github.com/wiggin77/merror/LICENSE
generated
vendored
Normal file
@ -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.
|
2
vendor/github.com/wiggin77/merror/README.md
generated
vendored
Normal file
2
vendor/github.com/wiggin77/merror/README.md
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# merror
|
||||
Multiple Error aggregator for Golang.
|
43
vendor/github.com/wiggin77/merror/format.go
generated
vendored
Normal file
43
vendor/github.com/wiggin77/merror/format.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
1
vendor/github.com/wiggin77/merror/go.mod
generated
vendored
Normal file
1
vendor/github.com/wiggin77/merror/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
module github.com/wiggin77/merror
|
87
vendor/github.com/wiggin77/merror/merror.go
generated
vendored
Normal file
87
vendor/github.com/wiggin77/merror/merror.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
1
vendor/github.com/wiggin77/srslog/.gitignore
generated
vendored
Normal file
1
vendor/github.com/wiggin77/srslog/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
.cover
|
15
vendor/github.com/wiggin77/srslog/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/wiggin77/srslog/.travis.yml
generated
vendored
Normal file
@ -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
|
50
vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md
generated
vendored
Normal file
50
vendor/github.com/wiggin77/srslog/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@ -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/
|
27
vendor/github.com/wiggin77/srslog/LICENSE
generated
vendored
Normal file
27
vendor/github.com/wiggin77/srslog/LICENSE
generated
vendored
Normal file
@ -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.
|
147
vendor/github.com/wiggin77/srslog/README.md
generated
vendored
Normal file
147
vendor/github.com/wiggin77/srslog/README.md
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
[](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.
|
68
vendor/github.com/wiggin77/srslog/constants.go
generated
vendored
Normal file
68
vendor/github.com/wiggin77/srslog/constants.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
104
vendor/github.com/wiggin77/srslog/dialer.go
generated
vendored
Normal file
104
vendor/github.com/wiggin77/srslog/dialer.go
generated
vendored
Normal file
@ -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
|
||||
}
|
58
vendor/github.com/wiggin77/srslog/formatter.go
generated
vendored
Normal file
58
vendor/github.com/wiggin77/srslog/formatter.go
generated
vendored
Normal file
@ -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
|
||||
}
|
24
vendor/github.com/wiggin77/srslog/framer.go
generated
vendored
Normal file
24
vendor/github.com/wiggin77/srslog/framer.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
3
vendor/github.com/wiggin77/srslog/go.mod
generated
vendored
Normal file
3
vendor/github.com/wiggin77/srslog/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/wiggin77/srslog
|
||||
|
||||
go 1.14
|
13
vendor/github.com/wiggin77/srslog/logger.go
generated
vendored
Normal file
13
vendor/github.com/wiggin77/srslog/logger.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package srslog
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
)
|
||||
|
||||
var Logger log.Logger
|
||||
|
||||
func init() {
|
||||
Logger = log.Logger{}
|
||||
Logger.SetOutput(ioutil.Discard)
|
||||
}
|
76
vendor/github.com/wiggin77/srslog/net_conn.go
generated
vendored
Normal file
76
vendor/github.com/wiggin77/srslog/net_conn.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
125
vendor/github.com/wiggin77/srslog/srslog.go
generated
vendored
Normal file
125
vendor/github.com/wiggin77/srslog/srslog.go
generated
vendored
Normal file
@ -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
|
||||
}
|
54
vendor/github.com/wiggin77/srslog/srslog_unix.go
generated
vendored
Normal file
54
vendor/github.com/wiggin77/srslog/srslog_unix.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
201
vendor/github.com/wiggin77/srslog/writer.go
generated
vendored
Normal file
201
vendor/github.com/wiggin77/srslog/writer.go
generated
vendored
Normal file
@ -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
|
||||
}
|
Reference in New Issue
Block a user