blob: f1064ab2f2f3f6121466849a26e3c09b06a41860 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed 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 log
import (
"fmt"
"io"
"time"
)
// Style implementations are responsible for writing a log record to an io.Writer.
type Style func(w io.Writer, r Record)
func rawStyle(w io.Writer, r Record) bool {
if r.Raw == nil {
return false
}
raw := *r.Raw
if raw == "" {
fmt.Fprint(w, r.Message)
} else {
fmt.Fprint(w, raw, ":", r.Message)
}
return true
}
func detail(w io.Writer, r Record) {
if r.Detail == "" {
return
}
s := r.Detail
start := 0
for i, c := range s {
if c == '\n' {
fragment := s[start:i]
start = i + 1
fmt.Fprint(w, "\n ", fragment)
}
}
fragment := s[start:]
if len(fragment) > 0 {
fmt.Fprint(w, "\n ", fragment)
}
}
func Brief(w io.Writer, r Record) {
if rawStyle(w, r) {
return
}
fmt.Fprint(w, r.Severity)
if r.Cause != nil || r.Chain != nil {
fmt.Fprint(w, ":Failed")
}
if r.Message != "" {
fmt.Fprint(w, ":", r.Message)
}
if r.Cause != nil {
fmt.Fprint(w, "<", r.Cause, ">")
}
if r.Chain != nil {
fmt.Fprint(w, "<<")
Brief(w, *r.Chain)
fmt.Fprint(w, ">>")
}
}
func Normal(w io.Writer, r Record) {
if rawStyle(w, r) {
return
}
fmt.Fprint(w, r.Severity)
if top, ok := r.StackTrace.Current(r.StackFilter); ok {
fmt.Fprint(w, ":", top.File, ":", top.Line)
}
if r.Tag != "" {
fmt.Fprint(w, ":", r.Tag)
}
if r.Trace != nil {
fmt.Fprint(w, ":", r.Trace)
}
if r.Cause != nil {
fmt.Fprint(w, ":Failed")
}
if r.Message != "" {
fmt.Fprint(w, ":", r.Message)
}
if len(r.Properties) > 0 {
fmt.Fprint(w, ":")
for i := len(r.Properties) - 1; i >= 0; i-- {
doProperty(w, r.Properties[i], "")
if i > 0 {
fmt.Fprint(w, ",")
}
}
}
if r.Cause != nil {
fmt.Fprint(w, "<", r.Cause, ">")
}
if r.Chain != nil {
fmt.Fprint(w, "<<")
Normal(w, *r.Chain)
fmt.Fprint(w, ">>")
}
detail(w, r)
}
const indentStep = " "
func Detailed(w io.Writer, r Record) {
if rawStyle(w, r) {
return
}
doDetailed(w, r, "")
}
func doDetailed(w io.Writer, r Record, prefix string) {
indent := prefix + indentStep
fmt.Fprint(w, prefix, r.TimeStamp.Format(time.Stamp), ":", r.Severity)
if r.Tag != "" {
fmt.Fprint(w, ":", r.Tag)
}
if r.Trace != nil {
fmt.Fprint(w, ":", r.Trace)
}
if r.Cause != nil {
fmt.Fprint(w, ":Failed")
}
if r.Message != "" {
fmt.Fprint(w, ":", r.Message)
}
for i := len(r.Properties) - 1; i >= 0; i-- {
fmt.Fprintln(w)
doProperty(w, r.Properties[i], indent)
}
if r.Cause != nil {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "<", r.Cause, ">")
}
for _, call := range r.StackTrace.Calls(r.StackFilter) {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "• ", call.File, ":", call.Line, " ", call.Function)
}
if r.Chain != nil {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "<<")
fmt.Fprintln(w)
doDetailed(w, *r.Chain, indent)
fmt.Fprintln(w)
fmt.Fprint(w, indent, ">>")
}
detail(w, r)
}
func Structured(w io.Writer, r Record) {
if rawStyle(w, r) {
return
}
doStructured(w, r, "")
}
func doStructured(w io.Writer, r Record, prefix string) {
indent := prefix + indentStep
fmt.Fprint(w, prefix, r.Severity, ":", r.Message)
fmt.Fprintln(w)
fmt.Fprint(w, indent, "Time=", r.TimeStamp.Format(time.StampMilli))
if r.Tag != "" {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "Tag=", r.Tag)
}
if r.Trace != nil {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "Trace=", r.Trace)
}
if r.Cause != nil {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "Cause=", r.Cause)
}
for _, call := range r.StackTrace.Calls(r.StackFilter) {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "• ", call.File, ":", call.Line, " ", call.Package, " ", call.Function)
}
for i := len(r.Properties) - 1; i >= 0; i-- {
fmt.Fprintln(w)
doProperty(w, r.Properties[i], indent)
}
if r.Chain != nil {
fmt.Fprintln(w)
fmt.Fprint(w, indent, "<<")
fmt.Fprintln(w)
doStructured(w, *r.Chain, indent)
fmt.Fprintln(w)
fmt.Fprint(w, indent, ">>")
}
detail(w, r)
}
const maxLength = 512
const elide = "..."
func doProperty(w io.Writer, p Property, prefix string) {
s := fmt.Sprint(p.Value)
if len(s) > maxLength+len(elide) {
s = s[0:maxLength] + "..."
}
fmt.Fprint(w, prefix, p.Name, "=", s)
}