Repository: incubator-htrace Updated Branches: refs/heads/master 971365f11 -> fda9051a9
HTRACE-89. htraced: add log levels, writing to log files (cmccabe) Project: http://git-wip-us.apache.org/repos/asf/incubator-htrace/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-htrace/commit/fda9051a Tree: http://git-wip-us.apache.org/repos/asf/incubator-htrace/tree/fda9051a Diff: http://git-wip-us.apache.org/repos/asf/incubator-htrace/diff/fda9051a Branch: refs/heads/master Commit: fda9051a98e825ddf683f29fa0b8456eaea9fb9f Parents: 971365f Author: Colin P. Mccabe <[email protected]> Authored: Tue Jan 27 15:41:26 2015 -0800 Committer: Colin P. Mccabe <[email protected]> Committed: Tue Jan 27 15:41:26 2015 -0800 ---------------------------------------------------------------------- .../src/go/src/org/apache/htrace/common/log.go | 268 +++++++++++++++++++ .../src/go/src/org/apache/htrace/conf/config.go | 6 + .../src/org/apache/htrace/conf/config_keys.go | 8 + .../src/org/apache/htrace/htraced/datastore.go | 47 ++-- .../go/src/org/apache/htrace/htraced/htraced.go | 11 +- .../go/src/org/apache/htrace/htraced/rest.go | 50 ++-- 6 files changed, 352 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/common/log.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/common/log.go b/htrace-core/src/go/src/org/apache/htrace/common/log.go new file mode 100644 index 0000000..31faea4 --- /dev/null +++ b/htrace-core/src/go/src/org/apache/htrace/common/log.go @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package common + +import ( + "errors" + "fmt" + "org/apache/htrace/conf" + "os" + "path/filepath" + "sort" + "strings" + "sync" + "time" +) + +// A logSink is a place logs can be written to. +type logSink struct { + path logPath + file *os.File + lock sync.Mutex + refCount int // protected by logFilesLock +} + +// Write to the logSink. +func (sink *logSink) write(str string) { + sink.lock.Lock() + defer sink.lock.Unlock() + _, err := sink.file.Write([]byte(str)) + if err != nil { + fmt.Fprintf(os.Stderr, "Error logging to '%s': %s\n", sink.path, err.Error()) + } +} + +// Unreference the logSink. If there are no more references, and the logSink is +// closeable, then we will close it here. +func (sink *logSink) Unref() { + logFilesLock.Lock() + defer logFilesLock.Unlock() + sink.refCount-- + if sink.refCount <= 0 { + if sink.path.IsCloseable() { + err := sink.file.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "Error closing log file %s: %s\n", + sink.path, err.Error()) + } + } + logSinks[sink.path] = nil + } +} + +type logPath string + +// An empty LogPath represents "stdout." +const STDOUT_LOG_PATH = "" + +// Convert a path to a logPath. +func logPathFromString(path string) logPath { + if path == STDOUT_LOG_PATH { + return logPath("") + } + absPath, err := filepath.Abs(path) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to get absolute path of %s: %s\n", + path, err.Error()) + return logPath(path) + } + return logPath(absPath) +} + +// Convert the path to a human-readable string. +func (path logPath) String() string { + if path == "" { + return "(stdout)" + } else { + return string(path) + } +} + +// Return true if the path is closeable. stdout is not closeable. +func (path logPath) IsCloseable() bool { + return path != STDOUT_LOG_PATH +} + +func (path logPath) Open() *logSink { + if path == STDOUT_LOG_PATH { + return &logSink{path: path, file: os.Stdout} + } + file, err := os.OpenFile(string(path), os.O_WRONLY|os.O_APPEND, 0777) + if err != nil { + sink := &logSink{path: STDOUT_LOG_PATH, file: os.Stdout} + fmt.Fprintf(os.Stderr, "Failed to open log file %s: %s\n", + path, err.Error()) + return sink + } + return &logSink{path: path, file: file} +} + +var logFilesLock sync.Mutex + +var logSinks map[logPath]*logSink = make(map[logPath]*logSink) + +func getOrCreateLogSink(pathStr string) *logSink { + path := logPathFromString(pathStr) + logFilesLock.Lock() + defer logFilesLock.Unlock() + sink := logSinks[path] + if sink == nil { + sink = path.Open() + logSinks[path] = sink + } + sink.refCount++ + return sink +} + +type Level int + +const ( + TRACE Level = iota + DEBUG + INFO + WARN + ERROR +) + +var levelToString map[Level]string = map[Level]string{ + TRACE: "TRACE", + DEBUG: "DEBUG", + INFO: "INFO", + WARN: "WARN", + ERROR: "ERROR", +} + +func (level Level) String() string { + return levelToString[level] +} + +func (level Level) LogString() string { + return level.String()[0:1] +} + +func LevelFromString(str string) (Level, error) { + for k, v := range levelToString { + if strings.ToLower(v) == strings.ToLower(str) { + return k, nil + } + } + var levelNames sort.StringSlice + levelNames = make([]string, len(levelToString)) + var i int + for _, v := range levelToString { + levelNames[i] = v + i++ + } + sort.Sort(levelNames) + return TRACE, errors.New(fmt.Sprintf("No such level as '%s'. Valid "+ + "levels are '%v'\n", str, levelNames)) +} + +type Logger struct { + sink *logSink + level Level +} + +func NewLogger(faculty string, cnf *conf.Config) *Logger { + path, level := parseConf(faculty, cnf) + sink := getOrCreateLogSink(path) + return &Logger{sink: sink, level: level} +} + +func parseConf(faculty string, cnf *conf.Config) (string, Level) { + facultyLogPathKey := faculty + "." + conf.HTRACE_LOG_PATH + var facultyLogPath string + if cnf.Contains(facultyLogPathKey) { + facultyLogPath = cnf.Get(facultyLogPathKey) + } else { + facultyLogPath = cnf.Get(conf.HTRACE_LOG_PATH) + } + facultyLogLevelKey := faculty + conf.HTRACE_LOG_LEVEL + var facultyLogLevelStr string + if cnf.Contains(facultyLogLevelKey) { + facultyLogLevelStr = cnf.Get(facultyLogLevelKey) + } else { + facultyLogLevelStr = cnf.Get(conf.HTRACE_LOG_LEVEL) + } + level, err := LevelFromString(facultyLogLevelStr) + if err != nil { + fmt.Fprintf(os.Stderr, "Error configuring log level: %s. Using TRACE.\n") + level = TRACE + } + return facultyLogPath, level +} + +func (lg *Logger) Trace(str string) { + lg.write(TRACE, str) +} + +func (lg *Logger) Tracef(format string, v ...interface{}) { + lg.write(TRACE, fmt.Sprintf(format, v...)) +} + +func (lg *Logger) Debug(str string) { + lg.write(DEBUG, str) +} + +func (lg *Logger) Debugf(format string, v ...interface{}) { + lg.write(DEBUG, fmt.Sprintf(format, v...)) +} + +func (lg *Logger) Info(str string) { + lg.write(INFO, str) +} + +func (lg *Logger) Infof(format string, v ...interface{}) { + lg.write(INFO, fmt.Sprintf(format, v...)) +} + +func (lg *Logger) Warn(str string) error { + lg.write(WARN, str) + return errors.New(str) +} + +func (lg *Logger) Warnf(format string, v ...interface{}) error { + str := fmt.Sprintf(format, v...) + lg.write(WARN, str) + return errors.New(str) +} + +func (lg *Logger) Error(str string) error { + lg.write(ERROR, str) + return errors.New(str) +} + +func (lg *Logger) Errorf(format string, v ...interface{}) error { + str := fmt.Sprintf(format, v...) + lg.write(ERROR, str) + return errors.New(str) +} + +func (lg *Logger) write(level Level, str string) { + if level >= lg.level { + lg.sink.write(time.Now().Format(time.RFC3339) + " " + + level.LogString() + ": " + str) + } +} + +func (lg *Logger) Close() { + lg.sink.Unref() + lg.sink = nil +} http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/conf/config.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/conf/config.go b/htrace-core/src/go/src/org/apache/htrace/conf/config.go index 41e39fa..d905322 100644 --- a/htrace-core/src/go/src/org/apache/htrace/conf/config.go +++ b/htrace-core/src/go/src/org/apache/htrace/conf/config.go @@ -152,6 +152,12 @@ func (bld *Builder) Build() (*Config, error) { return &cnf, nil } +// Returns true if the configuration has a non-default value for the given key. +func (cnf *Config) Contains(key string) bool { + _, ok := cnf.settings[key] + return ok +} + // Get a string configuration key. func (cnf *Config) Get(key string) string { ret := cnf.settings[key] http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go b/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go index b4e5994..5e359f7 100644 --- a/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go +++ b/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go @@ -52,6 +52,12 @@ const HTRACE_DATA_STORE_CLEAR = "data.store.clear" // How many writes to buffer before applying backpressure to span senders. const HTRACE_DATA_STORE_SPAN_BUFFER_SIZE = "data.store.span.buffer.size" +// Path to put the logs from htrace, or the empty string to use stdout. +const HTRACE_LOG_PATH = "log.path" + +// The log level to use for the logs in htrace. +const HTRACE_LOG_LEVEL = "log.level" + // Default values for HTrace configuration keys. var DEFAULTS = map[string]string{ HTRACE_WEB_ADDRESS: fmt.Sprintf("0.0.0.0:%d", HTRACE_WEB_ADDRESS_DEFAULT_PORT), @@ -59,4 +65,6 @@ var DEFAULTS = map[string]string{ PATH_LIST_SEP + PATH_SEP + "tmp" + PATH_SEP + "htrace2", HTRACE_DATA_STORE_CLEAR: "false", HTRACE_DATA_STORE_SPAN_BUFFER_SIZE: "100", + HTRACE_LOG_PATH: "", + HTRACE_LOG_LEVEL: "INFO", } http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go b/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go index 2137063..40678bd 100644 --- a/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go +++ b/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go @@ -23,7 +23,6 @@ import ( "bytes" "encoding/gob" "github.com/jmhodges/levigo" - "log" "org/apache/htrace/common" "org/apache/htrace/conf" "os" @@ -163,18 +162,20 @@ func (shd *shard) WriteMetadata(meta *dataStoreMetadata) error { // Process incoming spans for a shard. func (shd *shard) processIncoming() { + lg := shd.store.lg for { span := <-shd.incoming if span == nil { - log.Printf("Shard processor for %s exiting.", shd.path) + lg.Infof("Shard processor for %s exiting.\n", shd.path) shd.exited <- true return } err := shd.writeSpan(span) if err != nil { - log.Fatal("Shard processor for %s got fatal error %s.", shd.path, err.Error()) + lg.Errorf("Shard processor for %s got fatal error %s.\n", shd.path, err.Error()) + } else { + lg.Tracef("Shard processor for %s wrote span %s.\n", shd.path, span.ToJson()) } - //log.Printf("Shard processor for %s wrote span %s.", shd.path, span.ToJson()) } } @@ -236,17 +237,20 @@ func (shd *shard) FindChildren(sid int64, childIds []common.SpanId, lim int32) ( // Close a shard. func (shd *shard) Close() { + lg := shd.store.lg shd.incoming <- nil - log.Printf("Waiting for %s to exit...", shd.path) + lg.Infof("Waiting for %s to exit...\n", shd.path) if shd.exited != nil { <-shd.exited } shd.ldb.Close() - log.Printf("Closed %s...", shd.path) + lg.Infof("Closed %s...\n", shd.path) } // The Data Store. type dataStore struct { + lg *common.Logger + // The shards which manage our LevelDB instances. shards []*shard @@ -272,7 +276,8 @@ func CreateDataStore(cnf *conf.Config, writtenSpans chan *common.Span) (*dataSto // If we return an error, close the store. var err error - store := &dataStore{shards: []*shard{}, WrittenSpans: writtenSpans} + lg := common.NewLogger("datastore", cnf) + store := &dataStore{lg: lg, shards: []*shard{}, WrittenSpans: writtenSpans} defer func() { if err != nil { store.Close() @@ -296,21 +301,21 @@ func CreateDataStore(cnf *conf.Config, writtenSpans chan *common.Span) (*dataSto } if !clearStored { // TODO: implement re-opening saved data - log.Println("Error: path " + path + "already exists.") + lg.Error("Error: path " + path + "already exists.") return nil, err } else { err = os.RemoveAll(path) if err != nil { - log.Println("Failed to create " + path + ": " + err.Error()) + lg.Error("Failed to create " + path + ": " + err.Error()) return nil, err } - log.Println("Cleared " + path) + lg.Info("Cleared " + path) } } var shd *shard shd, err = CreateShard(store, cnf, path) if err != nil { - log.Printf("Error creating shard %s: %s", path, err.Error()) + lg.Errorf("Error creating shard %s: %s", path, err.Error()) return nil, err } store.shards = append(store.shards, shd) @@ -320,7 +325,7 @@ func CreateDataStore(cnf *conf.Config, writtenSpans chan *common.Span) (*dataSto shd := store.shards[idx] err := shd.WriteMetadata(meta) if err != nil { - log.Println("Failed to write metadata to " + store.shards[idx].path + ": " + err.Error()) + lg.Error("Failed to write metadata to " + store.shards[idx].path + ": " + err.Error()) return nil, err } shd.exited = make(chan bool, 1) @@ -339,7 +344,7 @@ func CreateShard(store *dataStore, cnf *conf.Config, path string) (*shard, error //openOpts.SetFilterPolicy(filter) ldb, err := levigo.Open(path, openOpts) if err != nil { - log.Println("LevelDB failed to open " + path + ": " + err.Error()) + store.lg.Errorf("LevelDB failed to open %s: %s\n", path, err.Error()) return nil, err } defer func() { @@ -350,7 +355,7 @@ func CreateShard(store *dataStore, cnf *conf.Config, path string) (*shard, error spanBufferSize := cnf.GetInt(conf.HTRACE_DATA_STORE_SPAN_BUFFER_SIZE) shd = &shard{store: store, ldb: ldb, path: path, incoming: make(chan *common.Span, spanBufferSize)} - log.Println("LevelDB opened " + path) + store.lg.Infof("LevelDB opened %s\n", path) return shd, nil } @@ -362,12 +367,19 @@ func (store *dataStore) GetStatistics() *Statistics { func (store *dataStore) Close() { for idx := range store.shards { store.shards[idx].Close() + store.shards[idx] = nil } if store.readOpts != nil { store.readOpts.Close() + store.readOpts = nil } if store.writeOpts != nil { store.writeOpts.Close() + store.writeOpts = nil + } + if store.lg != nil { + store.lg.Close() + store.lg = nil } } @@ -385,12 +397,13 @@ func (store *dataStore) FindSpan(sid int64) *common.Span { } func (shd *shard) FindSpan(sid int64) *common.Span { + lg := shd.store.lg buf, err := shd.ldb.Get(shd.store.readOpts, makeKey('s', sid)) if err != nil { if strings.Index(err.Error(), "NotFound:") != -1 { return nil } - log.Printf("Shard(%s): FindSpan(%016x) error: %s\n", + lg.Warnf("Shard(%s): FindSpan(%016x) error: %s\n", shd.path, sid, err.Error()) return nil } @@ -399,7 +412,7 @@ func (shd *shard) FindSpan(sid int64) *common.Span { data := common.SpanData{} err = decoder.Decode(&data) if err != nil { - log.Printf("Shard(%s): FindSpan(%016x) decode error: %s\n", + lg.Errorf("Shard(%s): FindSpan(%016x) decode error: %s\n", shd.path, sid, err.Error()) return nil } @@ -426,7 +439,7 @@ func (store *dataStore) FindChildren(sid int64, lim int32) []common.SpanId { shd := store.shards[idx] childIds, lim, err = shd.FindChildren(sid, childIds, lim) if err != nil { - log.Printf("Shard(%s): FindChildren(%016x) error: %s\n", + store.lg.Errorf("Shard(%s): FindChildren(%016x) error: %s\n", shd.path, sid, err.Error()) } idx++ http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go b/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go index d444a02..4694789 100644 --- a/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go +++ b/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go @@ -20,8 +20,9 @@ package main import ( - "log" + "org/apache/htrace/common" "org/apache/htrace/conf" + "os" "time" ) @@ -30,13 +31,17 @@ var GIT_VERSION string func main() { cnf := conf.LoadApplicationConfig(nil) + lg := common.NewLogger("main", cnf) + defer lg.Close() store, err := CreateDataStore(cnf, nil) if err != nil { - log.Fatalf("Error creating datastore: %s\n", err.Error()) + lg.Errorf("Error creating datastore: %s\n", err.Error()) + os.Exit(1) } _, err = CreateRestServer(cnf, store) if err != nil { - log.Fatalf("Error creating REST server: %s\n", err.Error()) + lg.Errorf("Error creating REST server: %s\n", err.Error()) + os.Exit(1) } for { time.Sleep(time.Duration(10) * time.Hour) http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/fda9051a/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go ---------------------------------------------------------------------- diff --git a/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go b/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go index d175f4e..efc89e1 100644 --- a/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go +++ b/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go @@ -24,7 +24,6 @@ import ( "fmt" "github.com/gorilla/mux" "io" - "log" "mime" "net" "net/http" @@ -42,23 +41,25 @@ func setResponseHeaders(hdr http.Header) { } // Write a JSON error response. -func writeError(w http.ResponseWriter, errCode int, errStr string) { +func writeError(lg *common.Logger, w http.ResponseWriter, errCode int, + errStr string) { str := strings.Replace(errStr, `"`, `'`, -1) - log.Println(str) + lg.Info(str) w.WriteHeader(errCode) w.Write([]byte(`{ "error" : "` + str + `"}`)) } type serverInfoHandler struct { + lg *common.Logger } -func (handler *serverInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (hand *serverInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { setResponseHeaders(w.Header()) version := common.ServerInfo{ReleaseVersion: RELEASE_VERSION, GitVersion: GIT_VERSION} buf, err := json.Marshal(&version) if err != nil { - writeError(w, http.StatusInternalServerError, + writeError(hand.lg, w, http.StatusInternalServerError, fmt.Sprintf("error marshalling ServerInfo: %s\n", err.Error())) return } @@ -66,13 +67,14 @@ func (handler *serverInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Req } type dataStoreHandler struct { + lg *common.Logger store *dataStore } func (hand *dataStoreHandler) parse64(w http.ResponseWriter, str string) (int64, bool) { val, err := strconv.ParseUint(str, 16, 64) if err != nil { - writeError(w, http.StatusBadRequest, + writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Failed to parse span ID %s: %s", str, err.Error())) w.Write([]byte("Error parsing : " + err.Error())) return -1, false @@ -84,12 +86,12 @@ func (hand *dataStoreHandler) getReqField32(fieldName string, w http.ResponseWri req *http.Request) (int32, bool) { str := req.FormValue(fieldName) if str == "" { - writeError(w, http.StatusBadRequest, fmt.Sprintf("No %s specified.", fieldName)) + writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("No %s specified.", fieldName)) return -1, false } val, err := strconv.ParseUint(str, 16, 32) if err != nil { - writeError(w, http.StatusBadRequest, + writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Error parsing %s: %s.", fieldName, err.Error())) return -1, false } @@ -111,7 +113,7 @@ func (hand *findSidHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) } span := hand.store.FindSpan(sid) if span == nil { - writeError(w, http.StatusNoContent, fmt.Sprintf("No such span as %s", + writeError(hand.lg, w, http.StatusNoContent, fmt.Sprintf("No such span as %s\n", common.SpanId(sid))) return } @@ -157,7 +159,7 @@ func (hand *writeSpansHandler) ServeHTTP(w http.ResponseWriter, req *http.Reques err := dec.Decode(&span) if err != nil { if err != io.EOF { - writeError(w, http.StatusBadRequest, + writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Error parsing spans: %s", err.Error())) return } @@ -166,12 +168,13 @@ func (hand *writeSpansHandler) ServeHTTP(w http.ResponseWriter, req *http.Reques spans = append(spans, &span) } for spanIdx := range spans { - log.Printf("writing span %s\n", spans[spanIdx].ToJson()) + hand.lg.Debugf("writing span %s\n", spans[spanIdx].ToJson()) hand.store.WriteSpan(spans[spanIdx]) } } type defaultServeHandler struct { + lg *common.Logger } func (hand *defaultServeHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { @@ -182,7 +185,7 @@ func (hand *defaultServeHandler) ServeHTTP(w http.ResponseWriter, req *http.Requ ident = strings.Replace(ident, "/", "__", -1) rsc := resource.Catalog[ident] if rsc == "" { - log.Printf("failed to find entry for %s\n", ident) + hand.lg.Warnf("failed to find entry for %s\n", ident) w.WriteHeader(http.StatusNotFound) return } @@ -194,6 +197,7 @@ func (hand *defaultServeHandler) ServeHTTP(w http.ResponseWriter, req *http.Requ type RestServer struct { listener net.Listener + lg *common.Logger } func CreateRestServer(cnf *conf.Config, store *dataStore) (*RestServer, error) { @@ -203,26 +207,36 @@ func CreateRestServer(cnf *conf.Config, store *dataStore) (*RestServer, error) { if err != nil { return nil, err } + var success bool + defer func() { + if !success { + rsv.Close() + } + }() + rsv.lg = common.NewLogger("rest", cnf) r := mux.NewRouter().StrictSlash(false) // Default Handler. This will serve requests for static requests. - r.Handle("/", &defaultServeHandler{}) + r.Handle("/", &defaultServeHandler{lg: rsv.lg}) - r.Handle("/server/info", &serverInfoHandler{}).Methods("GET") + r.Handle("/server/info", &serverInfoHandler{lg: rsv.lg}).Methods("GET") - writeSpansH := &writeSpansHandler{dataStoreHandler: dataStoreHandler{store: store}} + writeSpansH := &writeSpansHandler{dataStoreHandler: dataStoreHandler{ + store: store, lg: rsv.lg}} r.Handle("/writeSpans", writeSpansH).Methods("POST") span := r.PathPrefix("/span").Subrouter() - findSidH := &findSidHandler{dataStoreHandler: dataStoreHandler{store: store}} + findSidH := &findSidHandler{dataStoreHandler: dataStoreHandler{store: store, lg: rsv.lg}} span.Handle("/{id}", findSidH).Methods("GET") - findChildrenH := &findChildrenHandler{dataStoreHandler: dataStoreHandler{store: store}} + findChildrenH := &findChildrenHandler{dataStoreHandler: dataStoreHandler{store: store, + lg: rsv.lg}} span.Handle("/{id}/children", findChildrenH).Methods("GET") go http.Serve(rsv.listener, r) - log.Println("Started REST server...") + rsv.lg.Infof("Started REST server on %s...\n", rsv.listener.Addr().String()) + success = true return rsv, nil }
