@@ -77,6 +77,7 @@ import (
7777 "flag"
7878 "fmt"
7979 "io"
80+ stdLog "log"
8081 "os"
8182 "path/filepath"
8283 "runtime"
@@ -93,6 +94,9 @@ import (
9394// the corresponding constants in C++.
9495type severity int32 // sync/atomic int32
9596
97+ // These constants identify the log levels in order of increasing severity.
98+ // A message written to a high-severity log file is also written to each
99+ // lower-severity log file.
96100const (
97101 infoLog severity = iota
98102 warningLog
@@ -311,7 +315,7 @@ func (m *moduleSpec) Set(value string) error {
311315// isLiteral reports whether the pattern is a literal string, that is, has no metacharacters
312316// that require filepath.Match to be called to match the pattern.
313317func isLiteral (pattern string ) bool {
314- return ! strings .ContainsAny (pattern , `*?[]\ ` )
318+ return ! strings .ContainsAny (pattern , `\ *?[]` )
315319}
316320
317321// traceLocation represents the setting of the -log_backtrace_at flag.
@@ -513,7 +517,7 @@ var timeNow = time.Now // Stubbed out for testing.
513517
514518/*
515519header formats a log header as defined by the C++ implementation.
516- It returns a buffer containing the formatted header.
520+ It returns a buffer containing the formatted header and the user's file and line number .
517521
518522Log lines have this form:
519523 Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
@@ -527,9 +531,7 @@ where the fields are defined as follows:
527531 line The line number
528532 msg The user-supplied message
529533*/
530- func (l * loggingT ) header (s severity ) * buffer {
531- // Lmmdd hh:mm:ss.uuuuuu threadid file:line]
532- now := timeNow ()
534+ func (l * loggingT ) header (s severity ) (* buffer , string , int ) {
533535 _ , file , line , ok := runtime .Caller (3 ) // It's always the same number of frames to the user's call.
534536 if ! ok {
535537 file = "???"
@@ -540,6 +542,12 @@ func (l *loggingT) header(s severity) *buffer {
540542 file = file [slash + 1 :]
541543 }
542544 }
545+ return l .formatHeader (s , file , line ), file , line
546+ }
547+
548+ // formatHeader formats a log header using the provided file name and line number.
549+ func (l * loggingT ) formatHeader (s severity , file string , line int ) * buffer {
550+ now := timeNow ()
543551 if line < 0 {
544552 line = 0 // not a real line number, but acceptable to someDigits
545553 }
@@ -552,6 +560,7 @@ func (l *loggingT) header(s severity) *buffer {
552560 // It's worth about 3X. Fprintf is hard.
553561 _ , month , day := now .Date ()
554562 hour , minute , second := now .Clock ()
563+ // Lmmdd hh:mm:ss.uuuuuu threadid file:line]
555564 buf .tmp [0 ] = severityChar [s ]
556565 buf .twoDigits (1 , int (month ))
557566 buf .twoDigits (3 , day )
@@ -612,43 +621,54 @@ func (buf *buffer) someDigits(i, d int) int {
612621}
613622
614623func (l * loggingT ) println (s severity , args ... interface {}) {
615- buf := l .header (s )
624+ buf , file , line := l .header (s )
616625 fmt .Fprintln (buf , args ... )
617- l .output (s , buf )
626+ l .output (s , buf , file , line , false )
618627}
619628
620629func (l * loggingT ) print (s severity , args ... interface {}) {
621- buf := l .header (s )
630+ buf , file , line := l .header (s )
622631 fmt .Fprint (buf , args ... )
623632 if buf .Bytes ()[buf .Len ()- 1 ] != '\n' {
624633 buf .WriteByte ('\n' )
625634 }
626- l .output (s , buf )
635+ l .output (s , buf , file , line , false )
627636}
628637
629638func (l * loggingT ) printf (s severity , format string , args ... interface {}) {
630- buf := l .header (s )
639+ buf , file , line := l .header (s )
631640 fmt .Fprintf (buf , format , args ... )
632641 if buf .Bytes ()[buf .Len ()- 1 ] != '\n' {
633642 buf .WriteByte ('\n' )
634643 }
635- l .output (s , buf )
644+ l .output (s , buf , file , line , false )
645+ }
646+
647+ // printWithFileLine behaves like print but uses the provided file and line number. If
648+ // alsoLogToStderr is true, the log message always appears on standard error; it
649+ // will also appear in the log file unless --logtostderr is set.
650+ func (l * loggingT ) printWithFileLine (s severity , file string , line int , alsoToStderr bool , args ... interface {}) {
651+ buf := l .formatHeader (s , file , line )
652+ fmt .Fprint (buf , args ... )
653+ if buf .Bytes ()[buf .Len ()- 1 ] != '\n' {
654+ buf .WriteByte ('\n' )
655+ }
656+ l .output (s , buf , file , line , alsoToStderr )
636657}
637658
638659// output writes the data to the log files and releases the buffer.
639- func (l * loggingT ) output (s severity , buf * buffer ) {
660+ func (l * loggingT ) output (s severity , buf * buffer , file string , line int , alsoToStderr bool ) {
640661 l .mu .Lock ()
641662 if l .traceLocation .isSet () {
642- _ , file , line , ok := runtime .Caller (3 ) // It's always the same number of frames to the user's call (same as header).
643- if ok && l .traceLocation .match (file , line ) {
663+ if l .traceLocation .match (file , line ) {
644664 buf .Write (stacks (false ))
645665 }
646666 }
647667 data := buf .Bytes ()
648668 if l .toStderr {
649669 os .Stderr .Write (data )
650670 } else {
651- if l .alsoToStderr || s >= l .stderrThreshold .get () {
671+ if alsoToStderr || l .alsoToStderr || s >= l .stderrThreshold .get () {
652672 os .Stderr .Write (data )
653673 }
654674 if l .file [s ] == nil {
@@ -861,6 +881,54 @@ func (l *loggingT) flushAll() {
861881 }
862882}
863883
884+ // CopyStandardLogTo arranges for messages written to the Go "log" package's
885+ // default logs to also appear in the Google logs for the named and lower
886+ // severities. Subsequent changes to the standard log's default output location
887+ // or format may break this behavior.
888+ //
889+ // Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
890+ // recognized, CopyStandardLogTo panics.
891+ func CopyStandardLogTo (name string ) {
892+ sev , ok := severityByName (name )
893+ if ! ok {
894+ panic (fmt .Sprintf ("log.CopyStandardLogTo(%q): unrecognized severity name" , name ))
895+ }
896+ // Set a log format that captures the user's file and line:
897+ // d.go:23: message
898+ stdLog .SetFlags (stdLog .Lshortfile )
899+ stdLog .SetOutput (logBridge (sev ))
900+ }
901+
902+ // logBridge provides the Write method that enables CopyStandardLogTo to connect
903+ // Go's standard logs to the logs provided by this package.
904+ type logBridge severity
905+
906+ // Write parses the standard logging line and passes its components to the
907+ // logger for severity(lb).
908+ func (lb logBridge ) Write (b []byte ) (n int , err error ) {
909+ var (
910+ file = "???"
911+ line = 1
912+ text string
913+ )
914+ // Split "d.go:23: message" into "d.go", "23", and "message".
915+ if parts := bytes .SplitN (b , []byte {':' }, 3 ); len (parts ) != 3 || len (parts [0 ]) < 1 || len (parts [2 ]) < 1 {
916+ text = fmt .Sprintf ("bad log format: %s" , b )
917+ } else {
918+ file = string (parts [0 ])
919+ text = string (parts [2 ][1 :]) // skip leading space
920+ line , err = strconv .Atoi (string (parts [1 ]))
921+ if err != nil {
922+ text = fmt .Sprintf ("bad line number: %s" , b )
923+ line = 1
924+ }
925+ }
926+ // printWithFileLine with alsoToStderr=true, so standard log messages
927+ // always appear on standard error.
928+ logging .printWithFileLine (severity (lb ), file , line , true , text )
929+ return len (b ), nil
930+ }
931+
864932// setV computes and remembers the V level for a given PC
865933// when vmodule is enabled.
866934// File pattern matching takes the basename of the file, stripped
0 commit comments