github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/util/log.go (about) 1 // Copyright (c) 2014, Kevin Walsh. All rights reserved. 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 util 16 17 import ( 18 "bytes" 19 "fmt" 20 "runtime" 21 "strings" 22 "sync" 23 "text/tabwriter" 24 25 "github.com/golang/glog" 26 ) 27 28 const stackTraceDepth = 100 29 const showFileNames = true 30 31 var previousTrace []uintptr 32 var logging sync.Mutex 33 34 // Logged prints an error and some context to glog.Error, then returns the same 35 // error. The intended usage is like so: 36 // foo, err := somefunc() 37 // if err != nil { 38 // return 0, Logged(err) 39 // } 40 // ... 41 // The context consists of a stack trace, but omitting parts of the trace that 42 // were already shown by the most recently printed error. 43 func Logged(err error) error { 44 if err == nil { 45 return nil 46 } 47 // TODO(kwalsh) If glog.Error() will not print, maybe return early? 48 49 stackTrace := make([]uintptr, stackTraceDepth) 50 n := runtime.Callers(2, stackTrace) 51 stackTrace = stackTrace[:n] 52 53 logging.Lock() 54 defer logging.Unlock() 55 56 omit := 0 57 p := len(previousTrace) 58 for omit < n && omit < p && stackTrace[n-omit-1] == previousTrace[p-omit-1] { 59 omit++ 60 } 61 if omit < 2 { 62 omit = 0 63 } 64 65 var context bytes.Buffer 66 tabs := tabwriter.NewWriter(&context, 0, 8, 0, ' ', 0) 67 for i := 0; i < n-omit; i++ { 68 f := runtime.FuncForPC(stackTrace[i]) 69 place := "" 70 if showFileNames { 71 file, line := f.FileLine(stackTrace[i]) 72 parts := strings.SplitAfter(file, "/") 73 if len(parts) > 2 { 74 file = parts[len(parts)-2] + parts[len(parts)-1] 75 } 76 place = fmt.Sprintf("%s:%d", file, line) 77 } 78 fmt.Fprintf(tabs, " [%d]\t %s\t %s()\t\n", i+1, place, f.Name()) 79 } 80 if omit > 0 { 81 // TODO(kwalsh) maybe more info, e.g.: 82 // fmt.Fprintf(&context, " ... %d additional omitted\n", omit) 83 fmt.Fprintf(tabs, " ...\t\n") 84 } 85 tabs.Flush() 86 87 previousTrace = stackTrace 88 89 glog.Error(err.Error() + "; context:\n" + context.String()) 90 return err 91 }