json.go raw

   1  // Copyright 2018 The gVisor Authors.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License");
   4  // you may not use this file except in compliance with the License.
   5  // You may obtain a copy of the License at
   6  //
   7  //     http://www.apache.org/licenses/LICENSE-2.0
   8  //
   9  // Unless required by applicable law or agreed to in writing, software
  10  // distributed under the License is distributed on an "AS IS" BASIS,
  11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12  // See the License for the specific language governing permissions and
  13  // limitations under the License.
  14  
  15  package log
  16  
  17  import (
  18  	"encoding/json"
  19  	"fmt"
  20  	"runtime"
  21  	"strings"
  22  	"time"
  23  )
  24  
  25  type jsonLog struct {
  26  	Msg   string    `json:"msg"`
  27  	Level Level     `json:"level"`
  28  	Time  time.Time `json:"time"`
  29  }
  30  
  31  // MarshalJSON implements json.Marshaler.MarashalJSON.
  32  func (l Level) MarshalJSON() ([]byte, error) {
  33  	switch l {
  34  	case Warning:
  35  		return []byte(`"warning"`), nil
  36  	case Info:
  37  		return []byte(`"info"`), nil
  38  	case Debug:
  39  		return []byte(`"debug"`), nil
  40  	default:
  41  		return nil, fmt.Errorf("unknown level %v", l)
  42  	}
  43  }
  44  
  45  // UnmarshalJSON implements json.Unmarshaler.UnmarshalJSON.  It can unmarshal
  46  // from both string names and integers.
  47  func (l *Level) UnmarshalJSON(b []byte) error {
  48  	switch s := string(b); s {
  49  	case "0", `"warning"`:
  50  		*l = Warning
  51  	case "1", `"info"`:
  52  		*l = Info
  53  	case "2", `"debug"`:
  54  		*l = Debug
  55  	default:
  56  		return fmt.Errorf("unknown level %q", s)
  57  	}
  58  	return nil
  59  }
  60  
  61  // JSONEmitter logs messages in json format.
  62  type JSONEmitter struct {
  63  	*Writer
  64  }
  65  
  66  // Emit implements Emitter.Emit.
  67  func (e JSONEmitter) Emit(depth int, level Level, timestamp time.Time, format string, v ...any) {
  68  	logLine := fmt.Sprintf(format, v...)
  69  	if _, file, line, ok := runtime.Caller(depth + 1); ok {
  70  		if slash := strings.LastIndexByte(file, byte('/')); slash >= 0 {
  71  			file = file[slash+1:] // Trim any directory path from the file.
  72  		}
  73  		logLine = fmt.Sprintf("%s:%d] %s", file, line, logLine)
  74  	}
  75  	j := jsonLog{
  76  		Msg:   logLine,
  77  		Level: level,
  78  		Time:  timestamp,
  79  	}
  80  	b, err := json.Marshal(j)
  81  	if err != nil {
  82  		panic(err)
  83  	}
  84  	e.Writer.Write(b)
  85  }
  86