Initial commit
This commit is contained in:
26
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_option_helpers.go
generated
vendored
Normal file
26
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_option_helpers.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/hyperhq/hypercli/daemon/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultFailOnStartupError = true // So that we do not break existing behaviour
|
||||
)
|
||||
|
||||
// ParseFailOnStartupErrorFlag parses a log driver flag that determines if
|
||||
// the driver should ignore possible connection errors during startup
|
||||
func ParseFailOnStartupErrorFlag(ctx logger.Context) (bool, error) {
|
||||
failOnStartupError := ctx.Config["fail-on-startup-error"]
|
||||
if failOnStartupError == "" {
|
||||
return defaultFailOnStartupError, nil
|
||||
}
|
||||
failOnStartupErrorFlag, err := strconv.ParseBool(failOnStartupError)
|
||||
if err != nil {
|
||||
return defaultFailOnStartupError, fmt.Errorf("invalid connect error flag %s: %s", failOnStartupError, err)
|
||||
}
|
||||
return failOnStartupErrorFlag, nil
|
||||
}
|
||||
51
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_option_helpers_test.go
generated
vendored
Normal file
51
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_option_helpers_test.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hyperhq/hypercli/daemon/logger"
|
||||
)
|
||||
|
||||
func TestParseDefaultIgnoreFlag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{})
|
||||
flag, e := ParseFailOnStartupErrorFlag(ctx)
|
||||
assertFlag(t, e, flag, true)
|
||||
}
|
||||
|
||||
func TestParseIgnoreFlagWhenFalse(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"fail-on-startup-error": "false"})
|
||||
flag, e := ParseFailOnStartupErrorFlag(ctx)
|
||||
assertFlag(t, e, flag, false)
|
||||
}
|
||||
|
||||
func TestParseIgnoreFlagWhenTrue(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"fail-on-startup-error": "true"})
|
||||
flag, e := ParseFailOnStartupErrorFlag(ctx)
|
||||
assertFlag(t, e, flag, true)
|
||||
}
|
||||
|
||||
func TestParseIgnoreFlagWithError(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"fail-on-startup-error": "maybe :)"})
|
||||
flag, e := ParseFailOnStartupErrorFlag(ctx)
|
||||
if e == nil {
|
||||
t.Fatalf("Error should have happened")
|
||||
}
|
||||
assertFlag(t, nil, flag, true)
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
func buildConfig(cfg map[string]string) logger.Context {
|
||||
return logger.Context{
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func assertFlag(t *testing.T, e error, flag bool, expected bool) {
|
||||
if e != nil {
|
||||
t.Fatalf("Error parsing ignore connect error flag: %q", e)
|
||||
}
|
||||
if flag != expected {
|
||||
t.Fatalf("Wrong flag: %t, should be %t", flag, expected)
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_tag.go
generated
vendored
Normal file
46
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_tag.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hypercli/daemon/logger"
|
||||
)
|
||||
|
||||
// ParseLogTag generates a context aware tag for consistency across different
|
||||
// log drivers based on the context of the running container.
|
||||
func ParseLogTag(ctx logger.Context, defaultTemplate string) (string, error) {
|
||||
tagTemplate := lookupTagTemplate(ctx, defaultTemplate)
|
||||
|
||||
tmpl, err := template.New("log-tag").Parse(tagTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
if err := tmpl.Execute(buf, &ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func lookupTagTemplate(ctx logger.Context, defaultTemplate string) string {
|
||||
tagTemplate := ctx.Config["tag"]
|
||||
|
||||
deprecatedConfigs := []string{"syslog-tag", "gelf-tag", "fluentd-tag"}
|
||||
for i := 0; tagTemplate == "" && i < len(deprecatedConfigs); i++ {
|
||||
cfg := deprecatedConfigs[i]
|
||||
if ctx.Config[cfg] != "" {
|
||||
tagTemplate = ctx.Config[cfg]
|
||||
logrus.Warn(fmt.Sprintf("Using log tag from deprecated log-opt '%s'. Please use: --log-opt tag=\"%s\"", cfg, tagTemplate))
|
||||
}
|
||||
}
|
||||
|
||||
if tagTemplate == "" {
|
||||
tagTemplate = defaultTemplate
|
||||
}
|
||||
|
||||
return tagTemplate
|
||||
}
|
||||
58
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_tag_test.go
generated
vendored
Normal file
58
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/log_tag_test.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hyperhq/hypercli/daemon/logger"
|
||||
)
|
||||
|
||||
func TestParseLogTagDefaultTag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{})
|
||||
tag, e := ParseLogTag(ctx, "{{.ID}}")
|
||||
assertTag(t, e, tag, ctx.ID())
|
||||
}
|
||||
|
||||
func TestParseLogTag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"})
|
||||
tag, e := ParseLogTag(ctx, "{{.ID}}")
|
||||
assertTag(t, e, tag, "test-image/test-container/container-ab")
|
||||
}
|
||||
|
||||
func TestParseLogTagSyslogTag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"syslog-tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"})
|
||||
tag, e := ParseLogTag(ctx, "{{.ID}}")
|
||||
assertTag(t, e, tag, "test-image/test-container/container-ab")
|
||||
}
|
||||
|
||||
func TestParseLogTagGelfTag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"gelf-tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"})
|
||||
tag, e := ParseLogTag(ctx, "{{.ID}}")
|
||||
assertTag(t, e, tag, "test-image/test-container/container-ab")
|
||||
}
|
||||
|
||||
func TestParseLogTagFluentdTag(t *testing.T) {
|
||||
ctx := buildContext(map[string]string{"fluentd-tag": "{{.ImageName}}/{{.Name}}/{{.ID}}"})
|
||||
tag, e := ParseLogTag(ctx, "{{.ID}}")
|
||||
assertTag(t, e, tag, "test-image/test-container/container-ab")
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
func buildContext(cfg map[string]string) logger.Context {
|
||||
return logger.Context{
|
||||
ContainerID: "container-abcdefghijklmnopqrstuvwxyz01234567890",
|
||||
ContainerName: "/test-container",
|
||||
ContainerImageID: "image-abcdefghijklmnopqrstuvwxyz01234567890",
|
||||
ContainerImageName: "test-image",
|
||||
Config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func assertTag(t *testing.T, e error, tag string, expected string) {
|
||||
if e != nil {
|
||||
t.Fatalf("Error generating tag: %q", e)
|
||||
}
|
||||
if tag != expected {
|
||||
t.Fatalf("Wrong tag: %q, should be %q", tag, expected)
|
||||
}
|
||||
}
|
||||
132
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/rotatefilewriter.go
generated
vendored
Normal file
132
vendor/github.com/hyperhq/hypercli/daemon/logger/loggerutils/rotatefilewriter.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package loggerutils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/hyperhq/hypercli/pkg/pubsub"
|
||||
)
|
||||
|
||||
// RotateFileWriter is Logger implementation for default Docker logging.
|
||||
type RotateFileWriter struct {
|
||||
f *os.File // store for closing
|
||||
mu sync.Mutex
|
||||
capacity int64 //maximum size of each file
|
||||
maxFiles int //maximum number of files
|
||||
notifyRotate *pubsub.Publisher
|
||||
}
|
||||
|
||||
//NewRotateFileWriter creates new RotateFileWriter
|
||||
func NewRotateFileWriter(logPath string, capacity int64, maxFiles int) (*RotateFileWriter, error) {
|
||||
log, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
|
||||
if err != nil {
|
||||
return &RotateFileWriter{}, err
|
||||
}
|
||||
|
||||
return &RotateFileWriter{
|
||||
f: log,
|
||||
capacity: capacity,
|
||||
maxFiles: maxFiles,
|
||||
notifyRotate: pubsub.NewPublisher(0, 1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//WriteLog write log message to File
|
||||
func (w *RotateFileWriter) Write(message []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if err := w.checkCapacityAndRotate(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return w.f.Write(message)
|
||||
}
|
||||
|
||||
func (w *RotateFileWriter) checkCapacityAndRotate() error {
|
||||
if w.capacity == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
meta, err := w.f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if meta.Size() >= w.capacity {
|
||||
name := w.f.Name()
|
||||
if err := w.f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rotate(name, w.maxFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 06400)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.f = file
|
||||
w.notifyRotate.Publish(struct{}{})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rotate(name string, maxFiles int) error {
|
||||
if maxFiles < 2 {
|
||||
return nil
|
||||
}
|
||||
for i := maxFiles - 1; i > 1; i-- {
|
||||
toPath := name + "." + strconv.Itoa(i)
|
||||
fromPath := name + "." + strconv.Itoa(i-1)
|
||||
if err := backup(fromPath, toPath); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := backup(name, name+".1"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// backup renames a file from fromPath to toPath
|
||||
func backup(fromPath, toPath string) error {
|
||||
if _, err := os.Stat(fromPath); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(toPath); !os.IsNotExist(err) {
|
||||
err := os.Remove(toPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return os.Rename(fromPath, toPath)
|
||||
}
|
||||
|
||||
// LogPath returns the location the given writer logs to.
|
||||
func (w *RotateFileWriter) LogPath() string {
|
||||
return w.f.Name()
|
||||
}
|
||||
|
||||
// MaxFiles return maximum number of files
|
||||
func (w *RotateFileWriter) MaxFiles() int {
|
||||
return w.maxFiles
|
||||
}
|
||||
|
||||
//NotifyRotate returns the new subscriber
|
||||
func (w *RotateFileWriter) NotifyRotate() chan interface{} {
|
||||
return w.notifyRotate.Subscribe()
|
||||
}
|
||||
|
||||
//NotifyRotateEvict removes the specified subscriber from receiving any more messages.
|
||||
func (w *RotateFileWriter) NotifyRotateEvict(sub chan interface{}) {
|
||||
w.notifyRotate.Evict(sub)
|
||||
}
|
||||
|
||||
// Close closes underlying file and signals all readers to stop.
|
||||
func (w *RotateFileWriter) Close() error {
|
||||
return w.f.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user