aboutsummaryrefslogtreecommitdiff
path: root/vendor/google.golang.org/appengine/internal/log_vm.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/google.golang.org/appengine/internal/log_vm.go')
-rw-r--r--vendor/google.golang.org/appengine/internal/log_vm.go109
1 files changed, 109 insertions, 0 deletions
diff --git a/vendor/google.golang.org/appengine/internal/log_vm.go b/vendor/google.golang.org/appengine/internal/log_vm.go
new file mode 100644
index 0000000..1e7c9f2
--- /dev/null
+++ b/vendor/google.golang.org/appengine/internal/log_vm.go
@@ -0,0 +1,109 @@
+// Copyright 2016 Google Inc. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+package internal
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+ "sync"
+ "time"
+)
+
+// jsonLogger writes logs in the JSON format required for Flex Logging. It can
+// be used concurrently.
+type jsonLogger struct {
+ mu sync.Mutex
+ enc *json.Encoder
+}
+
+type logLine struct {
+ Message string `json:"message"`
+ Timestamp logTimestamp `json:"timestamp"`
+ Severity string `json:"severity"`
+ TraceID string `json:"traceId,omitempty"`
+}
+
+type logTimestamp struct {
+ Seconds int64 `json:"seconds"`
+ Nanos int `json:"nanos"`
+}
+
+var (
+ logger *jsonLogger
+ loggerOnce sync.Once
+
+ logPath = "/var/log/app_engine/app.json"
+ stderrLogger = newJSONLogger(os.Stderr)
+ testLogger = newJSONLogger(ioutil.Discard)
+
+ levels = map[int64]string{
+ 0: "DEBUG",
+ 1: "INFO",
+ 2: "WARNING",
+ 3: "ERROR",
+ 4: "CRITICAL",
+ }
+)
+
+func globalLogger() *jsonLogger {
+ loggerOnce.Do(func() {
+ f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ log.Printf("failed to open/create log file, logging to stderr: %v", err)
+ logger = stderrLogger
+ return
+ }
+
+ logger = newJSONLogger(f)
+ })
+
+ return logger
+}
+
+func logf(ctx *context, level int64, format string, args ...interface{}) {
+ s := strings.TrimSpace(fmt.Sprintf(format, args...))
+ now := time.Now()
+
+ trace := ctx.req.Header.Get(traceHeader)
+ if i := strings.Index(trace, "/"); i > -1 {
+ trace = trace[:i]
+ }
+
+ line := &logLine{
+ Message: s,
+ Timestamp: logTimestamp{
+ Seconds: now.Unix(),
+ Nanos: now.Nanosecond(),
+ },
+ Severity: levels[level],
+ TraceID: trace,
+ }
+
+ if err := ctx.logger.emit(line); err != nil {
+ log.Printf("failed to write log line to file: %v", err)
+ }
+
+ log.Print(levels[level] + ": " + s)
+}
+
+func newJSONLogger(w io.Writer) *jsonLogger {
+ return &jsonLogger{
+ enc: json.NewEncoder(w),
+ }
+}
+
+func (l *jsonLogger) emit(line *logLine) error {
+ l.mu.Lock()
+ defer l.mu.Unlock()
+
+ return l.enc.Encode(line)
+}