mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #2769 from barakmich/new_logger
etcdmain: New logger
This commit is contained in:
commit
2299e35d99
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd",
|
||||
"GoVersion": "go1.4.1",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
@ -20,6 +20,10 @@
|
||||
"Comment": "v0.2.0-rc1-130-g6aa2da5",
|
||||
"Rev": "6aa2da5a7a905609c93036b9307185a04a5a84a5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/pkg/capnslog",
|
||||
"Rev": "9d5dd4632f9ece71bdf83d31253593a633e73df5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Rev": "bc946d07d1016848dfd2507f90f0859c9471681e"
|
||||
|
38
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/README.md
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/README.md
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# CoreOS Log
|
||||
|
||||
There are far too many logging packages out there, with varying degrees of licenses, far too many features (colorization, all sorts of log frameworks) or are just a pain to use (lack of `Fatalln()`?)
|
||||
|
||||
## Design Principles
|
||||
|
||||
* `package main` is the place where logging gets turned on and routed
|
||||
|
||||
A library should not touch log options, only generate log entries. Libraries are silent until main lets them speak.
|
||||
|
||||
* All log options are runtime-configurable.
|
||||
|
||||
Still the job of `main` to expose these configurations. `main` may delegate this to, say, a configuration webhook, but does so explicitly.
|
||||
|
||||
* There is one log object per package. It is registered under its repository and package name.
|
||||
|
||||
`main` activates logging for its repository and any dependency repositories it would also like to have output in its logstream. `main` also dictates at which level each subpackage logs.
|
||||
|
||||
* There is *one* output stream, and it is an `io.Writer` composed with a formatter.
|
||||
|
||||
Splitting streams is probably not the job of your program, but rather, your log aggregation framework. If you must split output streams, again, `main` configures this and you can write a very simple two-output struct that satisfies io.Writer.
|
||||
|
||||
Fancy colorful formatting and JSON output are beyond the scope of a basic logging framework -- they're application/log-collector dependant. These are, at best, provided as options, but more likely, provided by your application.
|
||||
|
||||
* Log objects are an interface
|
||||
|
||||
An object knows best how to print itself. Log objects can collect more interesting metadata if they wish, however, because text isn't going away anytime soon, they must all be marshalable to text. The simplest log object is a string, which returns itself. If you wish to do more fancy tricks for printing your log objects, see also JSON output -- introspect and write a formatter which can handle your advanced log interface. Making strings is the only thing guaranteed.
|
||||
|
||||
* Log levels have specific meanings:
|
||||
|
||||
* Critical: Unrecoverable. Must fail.
|
||||
* Error: Data has been lost, a request has failed for a bad reason, or a required resource has been lost
|
||||
* Warning: (Hopefully) Temporary conditions that may cause errors, but may work fine. A replica disappearing (that may reconnect) is a warning.
|
||||
* Notice: Normal, but important (uncommon) log information.
|
||||
* Info: Normal, working log information, everything is fine, but helpful notices for auditing or common operations.
|
||||
* Debug: Everything is still fine, but even common operations may be logged, and less helpful but more quantity of notices.
|
||||
* Trace: Anything goes, from logging every function call as part of a common operation, to tracing execution of a query.
|
||||
|
38
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/example/hello_dolly.go
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/example/hello_dolly.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
oldlog "log"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var log = capnslog.NewPackageLogger("github.com/coreos/pkg/capnslog/cmd", "main")
|
||||
var dlog = capnslog.NewPackageLogger("github.com/coreos/pkg/capnslog/cmd", "dolly")
|
||||
|
||||
func main() {
|
||||
rl := capnslog.MustRepoLogger("github.com/coreos/pkg/capnslog/cmd")
|
||||
capnslog.SetFormatter(capnslog.NewStringFormatter(os.Stderr))
|
||||
|
||||
// We can parse the log level configs from the command line
|
||||
if len(os.Args) > 1 {
|
||||
cfg, err := rl.ParseLogLevelConfig(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
rl.SetLogLevel(cfg)
|
||||
log.Infof("Setting output to %s", os.Args[1])
|
||||
}
|
||||
|
||||
// Send some messages at different levels to the different packages
|
||||
dlog.Infof("Hello Dolly")
|
||||
dlog.Warningf("Well hello, Dolly")
|
||||
log.Errorf("It's so nice to have you back where you belong")
|
||||
dlog.Debugf("You're looking swell, Dolly")
|
||||
dlog.Tracef("I can tell, Dolly")
|
||||
|
||||
// We also have control over the built-in "log" package.
|
||||
capnslog.SetGlobalLogLevel(capnslog.INFO)
|
||||
oldlog.Println("You're still glowin', you're still crowin', you're still lookin' strong")
|
||||
log.Fatalf("Dolly'll never go away again")
|
||||
}
|
55
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/formatters.go
generated
vendored
Normal file
55
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/formatters.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Formatter interface {
|
||||
Format(pkg string, level LogLevel, depth int, entries ...LogEntry)
|
||||
Flush()
|
||||
}
|
||||
|
||||
func NewStringFormatter(w io.Writer) *StringFormatter {
|
||||
return &StringFormatter{
|
||||
w: bufio.NewWriter(w),
|
||||
}
|
||||
}
|
||||
|
||||
type StringFormatter struct {
|
||||
w *bufio.Writer
|
||||
}
|
||||
|
||||
func (s *StringFormatter) Format(pkg string, l LogLevel, i int, entries ...LogEntry) {
|
||||
now := time.Now()
|
||||
y, m, d := now.Date()
|
||||
h, min, sec := now.Clock()
|
||||
s.w.WriteString(fmt.Sprintf("%d/%02d/%d %02d:%02d:%02d ", y, m, d, h, min, sec))
|
||||
s.writeEntries(pkg, l, i, entries...)
|
||||
}
|
||||
|
||||
func (s *StringFormatter) writeEntries(pkg string, _ LogLevel, _ int, entries ...LogEntry) {
|
||||
if pkg != "" {
|
||||
s.w.WriteString(pkg + ": ")
|
||||
}
|
||||
endsInNL := false
|
||||
for i, v := range entries {
|
||||
if i != 0 {
|
||||
s.w.WriteByte(' ')
|
||||
}
|
||||
str := v.LogString()
|
||||
endsInNL = strings.HasSuffix(str, "\n")
|
||||
s.w.WriteString(str)
|
||||
}
|
||||
if !endsInNL {
|
||||
s.w.WriteString("\n")
|
||||
}
|
||||
s.Flush()
|
||||
}
|
||||
|
||||
func (s *StringFormatter) Flush() {
|
||||
s.w.Flush()
|
||||
}
|
81
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/glog_formatter.go
generated
vendored
Normal file
81
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/glog_formatter.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var pid = os.Getpid()
|
||||
|
||||
type GlogFormatter struct {
|
||||
StringFormatter
|
||||
}
|
||||
|
||||
func NewGlogFormatter(w io.Writer) *GlogFormatter {
|
||||
g := &GlogFormatter{}
|
||||
g.w = bufio.NewWriter(w)
|
||||
return g
|
||||
}
|
||||
|
||||
func (g GlogFormatter) Format(pkg string, level LogLevel, depth int, entries ...LogEntry) {
|
||||
g.w.Write(GlogHeader(level, depth+1))
|
||||
g.StringFormatter.Format(pkg, level, depth+1, entries...)
|
||||
}
|
||||
|
||||
func GlogHeader(level LogLevel, depth int) []byte {
|
||||
// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
|
||||
now := time.Now()
|
||||
_, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
|
||||
if !ok {
|
||||
file = "???"
|
||||
line = 1
|
||||
} else {
|
||||
slash := strings.LastIndex(file, "/")
|
||||
if slash >= 0 {
|
||||
file = file[slash+1:]
|
||||
}
|
||||
}
|
||||
if line < 0 {
|
||||
line = 0 // not a real line number
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Grow(30)
|
||||
_, month, day := now.Date()
|
||||
hour, minute, second := now.Clock()
|
||||
buf.WriteString(level.Char())
|
||||
twoDigits(buf, int(month))
|
||||
twoDigits(buf, day)
|
||||
buf.WriteByte(' ')
|
||||
twoDigits(buf, hour)
|
||||
buf.WriteByte(':')
|
||||
twoDigits(buf, minute)
|
||||
buf.WriteByte(':')
|
||||
twoDigits(buf, second)
|
||||
buf.WriteByte('.')
|
||||
buf.WriteString(strconv.Itoa(now.Nanosecond() / 1000))
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(strconv.Itoa(pid))
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(file)
|
||||
buf.WriteByte(':')
|
||||
buf.WriteString(strconv.Itoa(line))
|
||||
buf.WriteByte(']')
|
||||
buf.WriteByte(' ')
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
const digits = "0123456789"
|
||||
|
||||
func twoDigits(b *bytes.Buffer, d int) {
|
||||
c2 := digits[d%10]
|
||||
d /= 10
|
||||
c1 := digits[d%10]
|
||||
b.WriteByte(c1)
|
||||
b.WriteByte(c2)
|
||||
}
|
25
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/log_hijack.go
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/log_hijack.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
pkg := NewPackageLogger("log", "")
|
||||
w := packageWriter{pkg}
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("")
|
||||
log.SetOutput(w)
|
||||
}
|
||||
|
||||
type packageWriter struct {
|
||||
pl *PackageLogger
|
||||
}
|
||||
|
||||
func (p packageWriter) Write(b []byte) (int, error) {
|
||||
if p.pl.level < INFO {
|
||||
return 0, nil
|
||||
}
|
||||
p.pl.internalLog(calldepth+2, INFO, BaseLogEntry(string(b)))
|
||||
return len(b), nil
|
||||
}
|
206
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/logmap.go
generated
vendored
Normal file
206
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/logmap.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// LogLevel is the set of all log levels.
|
||||
type LogLevel int8
|
||||
|
||||
const (
|
||||
// CRITICAL is the lowest log level; only errors which will end the program will be propagated.
|
||||
CRITICAL LogLevel = -1
|
||||
// ERROR is for errors that are not fatal but lead to troubling behavior.
|
||||
ERROR = 0
|
||||
// WARNING is for errors which are not fatal and not errors, but are unusual. Often sourced from misconfigurations.
|
||||
WARNING = 1
|
||||
// NOTICE is for normal but significant conditions.
|
||||
NOTICE = 2
|
||||
// INFO is a log level for common, everyday log updates.
|
||||
INFO = 3
|
||||
// DEBUG is the default hidden level for more verbose updates about internal processes.
|
||||
DEBUG = 4
|
||||
// TRACE is for (potentially) call by call tracing of programs.
|
||||
TRACE = 5
|
||||
)
|
||||
|
||||
// Char returns a single-character representation of the log level.
|
||||
func (l LogLevel) Char() string {
|
||||
switch l {
|
||||
case CRITICAL:
|
||||
return "C"
|
||||
case ERROR:
|
||||
return "E"
|
||||
case WARNING:
|
||||
return "W"
|
||||
case NOTICE:
|
||||
return "N"
|
||||
case INFO:
|
||||
return "I"
|
||||
case DEBUG:
|
||||
return "D"
|
||||
case TRACE:
|
||||
return "T"
|
||||
default:
|
||||
panic("Unhandled loglevel")
|
||||
}
|
||||
}
|
||||
|
||||
// ParseLevel translates some potential loglevel strings into their corresponding levels.
|
||||
func ParseLevel(s string) (LogLevel, error) {
|
||||
switch s {
|
||||
case "CRITICAL", "C":
|
||||
return CRITICAL, nil
|
||||
case "ERROR", "0", "E":
|
||||
return ERROR, nil
|
||||
case "WARNING", "1", "W":
|
||||
return WARNING, nil
|
||||
case "NOTICE", "2", "N":
|
||||
return NOTICE, nil
|
||||
case "INFO", "3", "I":
|
||||
return INFO, nil
|
||||
case "DEBUG", "4", "D":
|
||||
return DEBUG, nil
|
||||
case "TRACE", "5", "T":
|
||||
return TRACE, nil
|
||||
}
|
||||
return CRITICAL, errors.New("couldn't parse log level " + s)
|
||||
}
|
||||
|
||||
type RepoLogger map[string]*PackageLogger
|
||||
|
||||
// LogEntry is the generic interface for things which can be logged.
|
||||
// Implementing the single method LogString() on your objects allows you to
|
||||
// format them for logs/debugging as necessary.
|
||||
type LogEntry interface {
|
||||
LogString() string
|
||||
}
|
||||
|
||||
type loggerStruct struct {
|
||||
sync.Mutex
|
||||
repoMap map[string]RepoLogger
|
||||
formatter Formatter
|
||||
}
|
||||
|
||||
// logger is the global logger
|
||||
var logger = new(loggerStruct)
|
||||
|
||||
// SetGlobalLogLevel sets the log level for all packages in all repositories
|
||||
// registered with capnslog.
|
||||
func SetGlobalLogLevel(l LogLevel) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
for _, r := range logger.repoMap {
|
||||
r.setRepoLogLevelInternal(l)
|
||||
}
|
||||
}
|
||||
|
||||
// GetRepoLogger may return the handle to the repository's set of packages' loggers.
|
||||
func GetRepoLogger(repo string) (RepoLogger, error) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
r, ok := logger.repoMap[repo]
|
||||
if !ok {
|
||||
return nil, errors.New("no packages registered for repo " + repo)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// MustRepoLogger returns the handle to the repository's packages' loggers.
|
||||
func MustRepoLogger(repo string) RepoLogger {
|
||||
r, err := GetRepoLogger(repo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// SetRepoLogLevel sets the log level for all packages in the repository.
|
||||
func (r RepoLogger) SetRepoLogLevel(l LogLevel) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
r.setRepoLogLevelInternal(l)
|
||||
}
|
||||
|
||||
func (r RepoLogger) setRepoLogLevelInternal(l LogLevel) {
|
||||
for _, v := range r {
|
||||
v.level = l
|
||||
}
|
||||
}
|
||||
|
||||
// ParseLogLevelConfig parses a comma-separated string of "package=loglevel", in
|
||||
// order, and returns a map of the results, for use in SetLogLevel.
|
||||
func (r RepoLogger) ParseLogLevelConfig(conf string) (map[string]LogLevel, error) {
|
||||
setlist := strings.Split(conf, ",")
|
||||
out := make(map[string]LogLevel)
|
||||
for _, setstring := range setlist {
|
||||
setting := strings.Split(setstring, "=")
|
||||
if len(setting) != 2 {
|
||||
return nil, errors.New("oddly structured `pkg=level` option: " + setstring)
|
||||
}
|
||||
l, err := ParseLevel(setting[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[setting[0]] = l
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SetLogLevel takes a map of package names within a repository to their desired
|
||||
// loglevel, and sets the levels appropriately. Unknown packages are ignored.
|
||||
// "*" is a special package name that corresponds to all packages, and will be
|
||||
// processed first.
|
||||
func (r RepoLogger) SetLogLevel(m map[string]LogLevel) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
if l, ok := m["*"]; ok {
|
||||
r.setRepoLogLevelInternal(l)
|
||||
}
|
||||
for k, v := range m {
|
||||
l, ok := r[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
l.level = v
|
||||
}
|
||||
}
|
||||
|
||||
// SetFormatter sets the formatting function for all logs.
|
||||
func SetFormatter(f Formatter) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
logger.formatter = f
|
||||
}
|
||||
|
||||
// NewPackageLogger creates a package logger object.
|
||||
// This should be defined as a global var in your package, referencing your repo.
|
||||
func NewPackageLogger(repo string, pkg string) (p *PackageLogger) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
if logger.repoMap == nil {
|
||||
logger.repoMap = make(map[string]RepoLogger)
|
||||
}
|
||||
r, rok := logger.repoMap[repo]
|
||||
if !rok {
|
||||
logger.repoMap[repo] = make(RepoLogger)
|
||||
r = logger.repoMap[repo]
|
||||
}
|
||||
p, pok := r[pkg]
|
||||
if !pok {
|
||||
r[pkg] = &PackageLogger{
|
||||
pkg: pkg,
|
||||
level: INFO,
|
||||
}
|
||||
p = r[pkg]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type BaseLogEntry string
|
||||
|
||||
func (b BaseLogEntry) LogString() string {
|
||||
return string(b)
|
||||
}
|
176
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/pkg_logger.go
generated
vendored
Normal file
176
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/pkg_logger.go
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type PackageLogger struct {
|
||||
pkg string
|
||||
level LogLevel
|
||||
}
|
||||
|
||||
const calldepth = 3
|
||||
|
||||
func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...LogEntry) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
if logger.formatter != nil {
|
||||
logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PackageLogger) LevelAt(l LogLevel) bool {
|
||||
return p.level >= l
|
||||
}
|
||||
|
||||
// log stdlib compatibility
|
||||
|
||||
func (p *PackageLogger) Println(args ...interface{}) {
|
||||
if p.level < INFO {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, INFO, BaseLogEntry(fmt.Sprintln(args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Printf(format string, args ...interface{}) {
|
||||
if p.level < INFO {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, INFO, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Print(args ...interface{}) {
|
||||
if p.level < INFO {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, INFO, BaseLogEntry(fmt.Sprint(args...)))
|
||||
}
|
||||
|
||||
// Panic and fatal
|
||||
|
||||
func (p *PackageLogger) Panicf(format string, args ...interface{}) {
|
||||
s := fmt.Sprintf(format, args...)
|
||||
p.internalLog(calldepth, CRITICAL, BaseLogEntry(s))
|
||||
panic(s)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Panic(args ...interface{}) {
|
||||
s := fmt.Sprint(args...)
|
||||
p.internalLog(calldepth, CRITICAL, BaseLogEntry(s))
|
||||
panic(s)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
|
||||
s := fmt.Sprintf(format, args...)
|
||||
p.internalLog(calldepth, CRITICAL, BaseLogEntry(s))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Fatal(args ...interface{}) {
|
||||
s := fmt.Sprint(args...)
|
||||
p.internalLog(calldepth, CRITICAL, BaseLogEntry(s))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Error Functions
|
||||
|
||||
func (p *PackageLogger) Errorf(format string, args ...interface{}) {
|
||||
if p.level < ERROR {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, ERROR, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Error(entries ...LogEntry) {
|
||||
if p.level < ERROR {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, ERROR, entries...)
|
||||
}
|
||||
|
||||
// Warning Functions
|
||||
|
||||
func (p *PackageLogger) Warningf(format string, args ...interface{}) {
|
||||
if p.level < WARNING {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, WARNING, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Warning(entries ...LogEntry) {
|
||||
if p.level < WARNING {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, WARNING, entries...)
|
||||
}
|
||||
|
||||
// Notice Functions
|
||||
|
||||
func (p *PackageLogger) Noticef(format string, args ...interface{}) {
|
||||
if p.level < NOTICE {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, NOTICE, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Notice(entries ...LogEntry) {
|
||||
if p.level < NOTICE {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, NOTICE, entries...)
|
||||
}
|
||||
|
||||
// Info Functions
|
||||
|
||||
func (p *PackageLogger) Infof(format string, args ...interface{}) {
|
||||
if p.level < INFO {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, INFO, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Info(entries ...LogEntry) {
|
||||
if p.level < INFO {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, INFO, entries...)
|
||||
}
|
||||
|
||||
// Debug Functions
|
||||
|
||||
func (p *PackageLogger) Debugf(format string, args ...interface{}) {
|
||||
if p.level < DEBUG {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, DEBUG, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Debug(entries ...LogEntry) {
|
||||
if p.level < DEBUG {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, DEBUG, entries...)
|
||||
}
|
||||
|
||||
// Trace Functions
|
||||
|
||||
func (p *PackageLogger) Tracef(format string, args ...interface{}) {
|
||||
if p.level < TRACE {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, TRACE, BaseLogEntry(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Trace(entries ...LogEntry) {
|
||||
if p.level < TRACE {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, TRACE, entries...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Flush() {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
logger.formatter.Flush()
|
||||
}
|
48
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/syslog_formatter.go
generated
vendored
Normal file
48
Godeps/_workspace/src/github.com/coreos/pkg/capnslog/syslog_formatter.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package capnslog
|
||||
|
||||
import (
|
||||
"log/syslog"
|
||||
)
|
||||
|
||||
func NewSyslogFormatter(w *syslog.Writer) Formatter {
|
||||
return &syslogFormatter{w}
|
||||
}
|
||||
|
||||
func NewDefaultSyslogFormatter(tag string) (Formatter, error) {
|
||||
w, err := syslog.New(syslog.LOG_DEBUG, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewSyslogFormatter(w), nil
|
||||
}
|
||||
|
||||
type syslogFormatter struct {
|
||||
w *syslog.Writer
|
||||
}
|
||||
|
||||
func (s *syslogFormatter) Format(pkg string, l LogLevel, _ int, entries ...LogEntry) {
|
||||
for _, entry := range entries {
|
||||
str := entry.LogString()
|
||||
switch l {
|
||||
case CRITICAL:
|
||||
s.w.Crit(str)
|
||||
case ERROR:
|
||||
s.w.Err(str)
|
||||
case WARNING:
|
||||
s.w.Warning(str)
|
||||
case NOTICE:
|
||||
s.w.Notice(str)
|
||||
case INFO:
|
||||
s.w.Info(str)
|
||||
case DEBUG:
|
||||
s.w.Debug(str)
|
||||
case TRACE:
|
||||
s.w.Debug(str)
|
||||
default:
|
||||
panic("Unhandled loglevel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *syslogFormatter) Flush() {
|
||||
}
|
@ -17,7 +17,6 @@ package etcdmain
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@ -96,6 +95,10 @@ type config struct {
|
||||
// security
|
||||
clientTLSInfo, peerTLSInfo transport.TLSInfo
|
||||
|
||||
// logging
|
||||
debug bool
|
||||
logPkgs string
|
||||
|
||||
// unsafe
|
||||
forceNewCluster bool
|
||||
|
||||
@ -180,6 +183,10 @@ func NewConfig() *config {
|
||||
fs.BoolVar(&cfg.peerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.")
|
||||
fs.StringVar(&cfg.peerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
|
||||
|
||||
// logging
|
||||
fs.BoolVar(&cfg.debug, "debug", false, "Enable debug output to the logs.")
|
||||
fs.StringVar(&cfg.logPkgs, "log-packages", "", "Specify a particular log level for each etcd package.")
|
||||
|
||||
// unsafe
|
||||
fs.BoolVar(&cfg.forceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster")
|
||||
|
||||
@ -221,7 +228,7 @@ func (cfg *config) Parse(arguments []string) error {
|
||||
|
||||
err := flags.SetFlagsFromEnv(cfg.FlagSet)
|
||||
if err != nil {
|
||||
log.Fatalf("etcd: %v", err)
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
set := make(map[string]bool)
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -37,10 +36,14 @@ import (
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
"github.com/coreos/etcd/proxy"
|
||||
"github.com/coreos/etcd/rafthttp"
|
||||
|
||||
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
type dirType string
|
||||
|
||||
var log = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcdmain")
|
||||
|
||||
const (
|
||||
// the owner can make/remove files inside the directory
|
||||
privateDirMode = 0700
|
||||
@ -53,12 +56,13 @@ var (
|
||||
)
|
||||
|
||||
func Main() {
|
||||
capnslog.SetFormatter(capnslog.NewStringFormatter(os.Stderr))
|
||||
cfg := NewConfig()
|
||||
err := cfg.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
log.Printf("etcd: error verifying flags, %v. See 'etcd -help'.", err)
|
||||
os.Exit(2)
|
||||
log.Fatalf("error verifying flags, %v. See 'etcd -help'.", err)
|
||||
}
|
||||
setupLogging(cfg)
|
||||
|
||||
var stopped <-chan struct{}
|
||||
|
||||
@ -68,19 +72,19 @@ func Main() {
|
||||
|
||||
if cfg.dir == "" {
|
||||
cfg.dir = fmt.Sprintf("%v.etcd", cfg.name)
|
||||
log.Printf("etcd: no data-dir provided, using default data-dir ./%s", cfg.dir)
|
||||
log.Printf("no data-dir provided, using default data-dir ./%s", cfg.dir)
|
||||
}
|
||||
|
||||
which := identifyDataDirOrDie(cfg.dir)
|
||||
if which != dirEmpty {
|
||||
log.Printf("etcd: already initialized as %v before, starting as etcd %v...", which, which)
|
||||
log.Printf("already initialized as %v before, starting as etcd %v...", which, which)
|
||||
}
|
||||
|
||||
shouldProxy := cfg.isProxy() || which == dirProxy
|
||||
if !shouldProxy {
|
||||
stopped, err = startEtcd(cfg)
|
||||
if err == discovery.ErrFullCluster && cfg.shouldFallbackToProxy() {
|
||||
log.Printf("etcd: discovery cluster full, falling back to %s", fallbackFlagProxy)
|
||||
log.Printf("discovery cluster full, falling back to %s", fallbackFlagProxy)
|
||||
shouldProxy = true
|
||||
}
|
||||
}
|
||||
@ -90,10 +94,10 @@ func Main() {
|
||||
if err != nil {
|
||||
switch err {
|
||||
case discovery.ErrDuplicateID:
|
||||
log.Fatalf("etcd: member %s has previously registered with discovery service (%s), but the data-dir (%s) on disk cannot be found.",
|
||||
log.Fatalf("member %s has previously registered with discovery service (%s), but the data-dir (%s) on disk cannot be found.",
|
||||
cfg.name, cfg.durl, cfg.dir)
|
||||
default:
|
||||
log.Fatalf("etcd: %v", err)
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +120,7 @@ func startEtcd(cfg *config) (<-chan struct{}, error) {
|
||||
}
|
||||
|
||||
if !cfg.peerTLSInfo.Empty() {
|
||||
log.Printf("etcd: peerTLS: %s", cfg.peerTLSInfo)
|
||||
log.Printf("peerTLS: %s", cfg.peerTLSInfo)
|
||||
}
|
||||
plns := make([]net.Listener, 0)
|
||||
for _, u := range cfg.lpurls {
|
||||
@ -127,18 +131,18 @@ func startEtcd(cfg *config) (<-chan struct{}, error) {
|
||||
}
|
||||
|
||||
urlStr := u.String()
|
||||
log.Print("etcd: listening for peers on ", urlStr)
|
||||
log.Print("listening for peers on ", urlStr)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
l.Close()
|
||||
log.Print("etcd: stopping listening for peers on ", urlStr)
|
||||
log.Print("stopping listening for peers on ", urlStr)
|
||||
}
|
||||
}()
|
||||
plns = append(plns, l)
|
||||
}
|
||||
|
||||
if !cfg.clientTLSInfo.Empty() {
|
||||
log.Printf("etcd: clientTLS: %s", cfg.clientTLSInfo)
|
||||
log.Printf("clientTLS: %s", cfg.clientTLSInfo)
|
||||
}
|
||||
clns := make([]net.Listener, 0)
|
||||
for _, u := range cfg.lcurls {
|
||||
@ -149,11 +153,11 @@ func startEtcd(cfg *config) (<-chan struct{}, error) {
|
||||
}
|
||||
|
||||
urlStr := u.String()
|
||||
log.Print("etcd: listening for client requests on ", urlStr)
|
||||
log.Print("listening for client requests on ", urlStr)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
l.Close()
|
||||
log.Print("etcd: stopping listening for client requests on ", urlStr)
|
||||
log.Print("stopping listening for client requests on ", urlStr)
|
||||
}
|
||||
}()
|
||||
clns = append(clns, l)
|
||||
@ -185,7 +189,7 @@ func startEtcd(cfg *config) (<-chan struct{}, error) {
|
||||
osutil.RegisterInterruptHandler(s.Stop)
|
||||
|
||||
if cfg.corsInfo.String() != "" {
|
||||
log.Printf("etcd: cors = %s", cfg.corsInfo)
|
||||
log.Printf("cors = %s", cfg.corsInfo)
|
||||
}
|
||||
ch := &cors.CORSHandler{
|
||||
Handler: etcdhttp.NewClientHandler(s),
|
||||
@ -363,7 +367,7 @@ func identifyDataDirOrDie(dir string) dirType {
|
||||
if os.IsNotExist(err) {
|
||||
return dirEmpty
|
||||
}
|
||||
log.Fatalf("etcd: error listing data dir: %s", dir)
|
||||
log.Fatalf("error listing data dir: %s", dir)
|
||||
}
|
||||
|
||||
var m, p bool
|
||||
@ -374,12 +378,12 @@ func identifyDataDirOrDie(dir string) dirType {
|
||||
case dirProxy:
|
||||
p = true
|
||||
default:
|
||||
log.Printf("etcd: found invalid file/dir %s under data dir %s (Ignore this if you are upgrading etcd)", name, dir)
|
||||
log.Printf("found invalid file/dir %s under data dir %s (Ignore this if you are upgrading etcd)", name, dir)
|
||||
}
|
||||
}
|
||||
|
||||
if m && p {
|
||||
log.Fatal("etcd: invalid datadir. Both member and proxy directories exist.")
|
||||
log.Fatal("invalid datadir. Both member and proxy directories exist.")
|
||||
}
|
||||
if m {
|
||||
return dirMember
|
||||
@ -389,3 +393,19 @@ func identifyDataDirOrDie(dir string) dirType {
|
||||
}
|
||||
return dirEmpty
|
||||
}
|
||||
|
||||
func setupLogging(cfg *config) {
|
||||
capnslog.SetGlobalLogLevel(capnslog.INFO)
|
||||
if cfg.debug {
|
||||
capnslog.SetGlobalLogLevel(capnslog.DEBUG)
|
||||
}
|
||||
if cfg.logPkgs != "" {
|
||||
repoLog := capnslog.MustRepoLogger("github.com/coreos/etcd")
|
||||
settings, err := repoLog.ParseLogLevelConfig(cfg.logPkgs)
|
||||
if err != nil {
|
||||
log.Warningf("Couldn't parse log level string: %s, continuing with default levels", err.Error())
|
||||
return
|
||||
}
|
||||
repoLog.SetLogLevel(settings)
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ package etcdmain
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
defaultLog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
@ -26,7 +26,7 @@ import (
|
||||
// creating a new service goroutine for each. The service goroutines
|
||||
// read requests and then call handler to reply to them.
|
||||
func serveHTTP(l net.Listener, handler http.Handler, readTimeout time.Duration) error {
|
||||
logger := log.New(ioutil.Discard, "etcdhttp", 0)
|
||||
logger := defaultLog.New(ioutil.Discard, "etcdhttp", 0)
|
||||
// TODO: add debug flag; enable logging when debug flag is set
|
||||
srv := &http.Server{
|
||||
Handler: handler,
|
||||
|
Loading…
x
Reference in New Issue
Block a user