Merge "lib/vlog: update to latest version of llog adding 'Depth' methods."
diff --git a/vlog/.api b/vlog/.api
index 667703c..c4668cd 100644
--- a/vlog/.api
+++ b/vlog/.api
@@ -2,17 +2,22 @@
 pkg vlog, func ConfigureLibraryLoggerFromFlags() error
 pkg vlog, func ConfigureLoggerFromFlags(Logger) error
 pkg vlog, func Error(...interface{})
+pkg vlog, func ErrorDepth(int, ...interface{})
 pkg vlog, func Errorf(string, ...interface{})
 pkg vlog, func Fatal(...interface{})
+pkg vlog, func FatalDepth(int, ...interface{})
 pkg vlog, func Fatalf(string, ...interface{})
 pkg vlog, func FlushLog()
 pkg vlog, func Info(...interface{})
+pkg vlog, func InfoDepth(int, ...interface{})
 pkg vlog, func InfoStack(bool)
 pkg vlog, func Infof(string, ...interface{})
+pkg vlog, func InfofDepth(int, string, ...interface{})
 pkg vlog, func LogCall(...interface{}) func(...interface{})
 pkg vlog, func LogCallf(string, ...interface{}) func(string, ...interface{})
 pkg vlog, func NewLogger(string) Logger
 pkg vlog, func Panic(...interface{})
+pkg vlog, func PanicDepth(int, ...interface{})
 pkg vlog, func Panicf(string, ...interface{})
 pkg vlog, func Stats() LevelStats
 pkg vlog, func V(Level) bool
@@ -25,6 +30,7 @@
 pkg vlog, method (*StderrThreshold) String() string
 pkg vlog, method (AlsoLogToStderr) LoggingOpt()
 pkg vlog, method (AutoFlush) LoggingOpt()
+pkg vlog, method (FilepathSpec) LoggingOpt()
 pkg vlog, method (Level) LoggingOpt()
 pkg vlog, method (LogDir) LoggingOpt()
 pkg vlog, method (LogToStderr) LoggingOpt()
@@ -35,26 +41,35 @@
 pkg vlog, method (TraceLocation) LoggingOpt()
 pkg vlog, type AlsoLogToStderr bool
 pkg vlog, type AutoFlush bool
-pkg vlog, type InfoLog interface { Info, InfoStack, Infof }
+pkg vlog, type FilepathSpec struct
+pkg vlog, type FilepathSpec struct, embedded llog.FilepathSpec
+pkg vlog, type InfoLog interface { Info, InfoDepth, InfoStack, Infof, InfofDepth }
 pkg vlog, type InfoLog interface, Info(...interface{})
+pkg vlog, type InfoLog interface, InfoDepth(int, ...interface{})
 pkg vlog, type InfoLog interface, InfoStack(bool)
 pkg vlog, type InfoLog interface, Infof(string, ...interface{})
+pkg vlog, type InfoLog interface, InfofDepth(int, string, ...interface{})
 pkg vlog, type Level llog.Level
 pkg vlog, type LevelStats llog.Stats
 pkg vlog, type LogDir string
 pkg vlog, type LogToStderr bool
-pkg vlog, type Logger interface { Configure, Error, Errorf, Fatal, Fatalf, FlushLog, Info, InfoStack, Infof, LogDir, Panic, Panicf, Stats, V, VI }
+pkg vlog, type Logger interface { Configure, Error, ErrorDepth, Errorf, Fatal, FatalDepth, Fatalf, FlushLog, Info, InfoDepth, InfoStack, Infof, InfofDepth, LogDir, Panic, PanicDepth, Panicf, Stats, V, VI }
 pkg vlog, type Logger interface, Configure(...LoggingOpts) error
 pkg vlog, type Logger interface, Error(...interface{})
+pkg vlog, type Logger interface, ErrorDepth(int, ...interface{})
 pkg vlog, type Logger interface, Errorf(string, ...interface{})
 pkg vlog, type Logger interface, Fatal(...interface{})
+pkg vlog, type Logger interface, FatalDepth(int, ...interface{})
 pkg vlog, type Logger interface, Fatalf(string, ...interface{})
 pkg vlog, type Logger interface, FlushLog()
 pkg vlog, type Logger interface, Info(...interface{})
+pkg vlog, type Logger interface, InfoDepth(int, ...interface{})
 pkg vlog, type Logger interface, InfoStack(bool)
 pkg vlog, type Logger interface, Infof(string, ...interface{})
+pkg vlog, type Logger interface, InfofDepth(int, string, ...interface{})
 pkg vlog, type Logger interface, LogDir() string
 pkg vlog, type Logger interface, Panic(...interface{})
+pkg vlog, type Logger interface, PanicDepth(int, ...interface{})
 pkg vlog, type Logger interface, Panicf(string, ...interface{})
 pkg vlog, type Logger interface, Stats() LevelStats
 pkg vlog, type Logger interface, V(Level) bool
@@ -74,5 +89,5 @@
 pkg vlog, type Verbosity interface { V, VI }
 pkg vlog, type Verbosity interface, V(Level) bool
 pkg vlog, type Verbosity interface, VI(Level) InfoLog
-pkg vlog, var Configured error
+pkg vlog, var ErrConfigured error
 pkg vlog, var Log *logger
diff --git a/vlog/GO.PACKAGE b/vlog/GO.PACKAGE
index e33cb69..a46fa75 100644
--- a/vlog/GO.PACKAGE
+++ b/vlog/GO.PACKAGE
@@ -1,5 +1,5 @@
 {
 	"imports": [
-		{"allow": "github.com/cosmosnicolaou/llog"}
+		{"allow": "github.com/cosnicolaou/llog"}
 	]
 }
diff --git a/vlog/flags.go b/vlog/flags.go
index 16931fe..21a21d2 100644
--- a/vlog/flags.go
+++ b/vlog/flags.go
@@ -8,7 +8,7 @@
 	"flag"
 	"fmt"
 
-	"github.com/cosmosnicolaou/llog"
+	"github.com/cosnicolaou/llog"
 )
 
 var (
diff --git a/vlog/funcs.go b/vlog/funcs.go
index fd8c478..c7c7e23 100644
--- a/vlog/funcs.go
+++ b/vlog/funcs.go
@@ -5,7 +5,7 @@
 package vlog
 
 import (
-	"github.com/cosmosnicolaou/llog"
+	"github.com/cosnicolaou/llog"
 )
 
 // Info logs to the INFO log.
@@ -22,6 +22,20 @@
 	Log.maybeFlush()
 }
 
+// InfoDepth acts as Info but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Info.
+func InfoDepth(depth int, args ...interface{}) {
+	Log.log.PrintDepth(llog.InfoLog, depth, args...)
+	Log.maybeFlush()
+}
+
+// InfofDepth acts as Infof but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Infof.
+func InfofDepth(depth int, format string, args ...interface{}) {
+	Log.log.PrintfDepth(llog.InfoLog, depth, format, args...)
+	Log.maybeFlush()
+}
+
 // InfoStack logs the current goroutine's stack if the all parameter
 // is false, or the stacks of all goroutines if it's true.
 func InfoStack(all bool) {
@@ -56,6 +70,13 @@
 	Log.maybeFlush()
 }
 
+// ErrorDepth acts as Error but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Error.
+func ErrorDepth(depth int, args ...interface{}) {
+	Log.log.PrintDepth(llog.ErrorLog, depth, args...)
+	Log.maybeFlush()
+}
+
 // Errorf logs to the ERROR and INFO logs.
 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
 func Errorf(format string, args ...interface{}) {
@@ -70,6 +91,12 @@
 	Log.log.Print(llog.FatalLog, args...)
 }
 
+// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Fatal.
+func FatalDepth(depth int, args ...interface{}) {
+	Log.log.PrintDepth(llog.FatalLog, depth, args...)
+}
+
 // Fatalf logs to the FATAL, ERROR and INFO logs,
 // including a stack trace of all running goroutines, then calls os.Exit(255).
 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
@@ -97,6 +124,12 @@
 	Log.Panic(args...)
 }
 
+// PanicDepth acts as Panic but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Panic.
+func PanicDepth(depth int, args ...interface{}) {
+	Log.PanicDepth(depth, args...)
+}
+
 // Panicf is equivalent to Errorf() followed by a call to panic().
 func Panicf(format string, args ...interface{}) {
 	Log.Panicf(format, args...)
diff --git a/vlog/log.go b/vlog/log.go
index b1e7e13..d5a7a33 100644
--- a/vlog/log.go
+++ b/vlog/log.go
@@ -11,7 +11,7 @@
 	"runtime"
 	"sync"
 
-	"github.com/cosmosnicolaou/llog"
+	"github.com/cosnicolaou/llog"
 )
 
 const (
@@ -34,8 +34,8 @@
 }
 
 var (
-	Log        *logger
-	Configured = errors.New("logger has already been configured")
+	Log           *logger
+	ErrConfigured = errors.New("logger has already been configured")
 )
 
 const stackSkip = 1
@@ -66,7 +66,7 @@
 		}
 	}
 	if l.configured && !override {
-		return Configured
+		return ErrConfigured
 	}
 	for _, o := range opts {
 		switch v := o.(type) {
@@ -87,6 +87,8 @@
 			}
 		case ModuleSpec:
 			l.log.SetVModule(v.ModuleSpec)
+		case FilepathSpec:
+			l.log.SetVFilepath(v.FilepathSpec)
 		case TraceLocation:
 			l.log.SetTraceLocation(v.TraceLocation)
 		case StderrThreshold:
@@ -127,6 +129,20 @@
 	l.maybeFlush()
 }
 
+// InfoDepth acts as Info but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Info.
+func (l *logger) InfoDepth(depth int, args ...interface{}) {
+	l.log.PrintDepth(llog.InfoLog, depth, args...)
+	l.maybeFlush()
+}
+
+// InfofDepth acts as Infof but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Infof.
+func (l *logger) InfofDepth(depth int, format string, args ...interface{}) {
+	l.log.PrintfDepth(llog.InfoLog, depth, format, args...)
+	l.maybeFlush()
+}
+
 func infoStack(l *logger, all bool) {
 	n := initialMaxStackBufSize
 	var trace []byte
@@ -155,9 +171,11 @@
 
 type discardInfo struct{}
 
-func (_ *discardInfo) Info(args ...interface{})                 {}
-func (_ *discardInfo) Infof(format string, args ...interface{}) {}
-func (_ *discardInfo) InfoStack(all bool)                       {}
+func (_ *discardInfo) Info(...interface{})                          {}
+func (_ *discardInfo) Infof(_ string, _ ...interface{})             {}
+func (_ *discardInfo) InfoDepth(_ int, _ ...interface{})            {}
+func (_ *discardInfo) InfofDepth(_ int, _ string, _ ...interface{}) {}
+func (_ *discardInfo) InfoStack(_ bool)                             {}
 
 func (l *logger) VI(v Level) InfoLog {
 	if l.log.V(llog.Level(v)) {
@@ -178,6 +196,13 @@
 	l.maybeFlush()
 }
 
+// ErrorDepth acts as Error but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Error.
+func (l *logger) ErrorDepth(depth int, args ...interface{}) {
+	l.log.PrintDepth(llog.ErrorLog, depth, args...)
+	l.maybeFlush()
+}
+
 // Errorf logs to the ERROR and INFO logs.
 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
 func (l *logger) Errorf(format string, args ...interface{}) {
@@ -192,6 +217,12 @@
 	l.log.Print(llog.FatalLog, args...)
 }
 
+// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Fatal.
+func (l *logger) FatalDepth(depth int, args ...interface{}) {
+	l.log.PrintDepth(llog.FatalLog, depth, args...)
+}
+
 // Fatalf logs to the FATAL, ERROR and INFO logs,
 // including a stack trace of all running goroutines, then calls os.Exit(255).
 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
@@ -205,6 +236,13 @@
 	panic(fmt.Sprint(args...))
 }
 
+// PanicDepth acts as Panic but uses depth to determine which call frame to log.
+// A depth of 0 is equivalent to calling Panic.
+func (l *logger) PanicDepth(depth int, args ...interface{}) {
+	l.ErrorDepth(depth, args...)
+	panic(fmt.Sprint(args...))
+}
+
 // Panicf is equivalent to Errorf() followed by a call to panic().
 func (l *logger) Panicf(format string, args ...interface{}) {
 	l.Errorf(format, args...)
diff --git a/vlog/log_test.go b/vlog/log_test.go
index 9243554..1e09263 100644
--- a/vlog/log_test.go
+++ b/vlog/log_test.go
@@ -72,7 +72,7 @@
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	fileRE := regexp.MustCompile(`\S+ \S+ \S+ (.*):.*`)
+	fileRE := regexp.MustCompile(`\S+ \S+\s+\S+ (.*):.*`)
 	for _, line := range contents {
 		name := fileRE.FindStringSubmatch(line)
 		if len(name) < 2 {
@@ -89,6 +89,43 @@
 	}
 }
 
+func TestDepth(t *testing.T) {
+	dir, err := ioutil.TempDir("", "logtest")
+	defer os.RemoveAll(dir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	logger := vlog.NewLogger("testHeader")
+	logger.Configure(vlog.LogDir(dir), vlog.Level(2))
+
+	logger.InfoDepth(0, "here\n")
+	tmp := func() {
+		logger.InfoDepth(1, "still here\n")
+		logger.InfoDepth(2, "not here\n")
+	}
+	tmp()
+	logger.FlushLog()
+	contents, err := readLogFiles(dir)
+	if err != nil {
+		t.Fatalf("unexpected error: %s", err)
+	}
+	fileRE := regexp.MustCompile(`\S+ \S+\s+\S+ (.*):.*`)
+	files := []string{}
+	for _, line := range contents {
+		name := fileRE.FindStringSubmatch(line)
+		if len(name) < 2 {
+			t.Errorf("failed to find file in %s", line)
+			continue
+		}
+		files = append(files, name[1])
+	}
+	for i, want := range []string{"log_test.go", "log_test.go", "testing.go"} {
+		if got := files[i]; got != want {
+			t.Errorf("%d: got %v, want %v", i, got, want)
+		}
+	}
+}
+
 func myLoggedFunc() {
 	f := vlog.LogCall("entry")
 	f("exit")
@@ -112,7 +149,7 @@
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	logCallLineRE := regexp.MustCompile(`\S+ \S+ \S+ ([^:]*):.*(call|return)\[(\S*)`)
+	logCallLineRE := regexp.MustCompile(`\S+ \S+\s+\S+ ([^:]*):.*(call|return)\[(\S*)`)
 	for _, line := range contents {
 		match := logCallLineRE.FindStringSubmatch(line)
 		if len(match) != 4 {
@@ -176,6 +213,54 @@
 	if vlog.VI(3) == vlog.Log {
 		t.Errorf("vlog.V(3) should not be vlog.Log")
 	}
+	spec = vlog.ModuleSpec{}
+	spec.Set("notlikelytobeinuse=2")
+	vlog.Log.Configure(vlog.OverridePriorConfiguration(true), spec)
+}
+
+func TestVFilepath(t *testing.T) {
+	dir, err := ioutil.TempDir("", "logtest")
+	defer os.RemoveAll(dir)
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	logger := vlog.NewLogger("testVmodule")
+	logger.Configure(vlog.LogDir(dir))
+	if logger.V(2) || logger.V(3) {
+		t.Errorf("Logging should not be enabled at levels 2 & 3")
+	}
+	spec := vlog.FilepathSpec{}
+	if err := spec.Set(".*log_test=2"); err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	if err := logger.Configure(vlog.OverridePriorConfiguration(true), spec); err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	if !logger.V(2) {
+		t.Errorf("logger.V(2) should be true")
+	}
+	if logger.V(3) {
+		t.Errorf("logger.V(3) should be false")
+	}
+	if vlog.V(2) || vlog.V(3) {
+		t.Errorf("Logging should not be enabled at levels 2 & 3")
+	}
+	vlog.Log.Configure(vlog.OverridePriorConfiguration(true), spec)
+	if !vlog.V(2) {
+		t.Errorf("vlog.V(2) should be true")
+	}
+	if vlog.V(3) {
+		t.Errorf("vlog.V(3) should be false")
+	}
+	if vlog.VI(2) != vlog.Log {
+		t.Errorf("vlog.V(2) should be vlog.Log")
+	}
+	if vlog.VI(3) == vlog.Log {
+		t.Errorf("vlog.V(3) should not be vlog.Log")
+	}
+	spec = vlog.FilepathSpec{}
+	spec.Set("notlikelytobeinuse=2")
+	vlog.Log.Configure(vlog.OverridePriorConfiguration(true), spec)
 }
 
 func TestConfigure(t *testing.T) {
@@ -188,7 +273,7 @@
 	if got, want := logger.Configure(vlog.LogDir(dir), vlog.AlsoLogToStderr(false)), error(nil); got != want {
 		t.Fatalf("got %v, want %v", got, want)
 	}
-	if got, want := logger.Configure(vlog.AlsoLogToStderr(true)), vlog.Configured; got != want {
+	if got, want := logger.Configure(vlog.AlsoLogToStderr(true)), vlog.ErrConfigured; got != want {
 		t.Fatalf("got %v, want %v", got, want)
 	}
 	if got, want := logger.Configure(vlog.OverridePriorConfiguration(true), vlog.AlsoLogToStderr(false)), error(nil); got != want {
diff --git a/vlog/logcall.go b/vlog/logcall.go
index b63e94c..f163a39 100644
--- a/vlog/logcall.go
+++ b/vlog/logcall.go
@@ -11,7 +11,7 @@
 	"runtime"
 	"sync/atomic"
 
-	"github.com/cosmosnicolaou/llog"
+	"github.com/cosnicolaou/llog"
 )
 
 // logCallLogLevel is the log level beyond which calls are logged.
diff --git a/vlog/model.go b/vlog/model.go
index 852f52c..ed00124 100644
--- a/vlog/model.go
+++ b/vlog/model.go
@@ -7,7 +7,7 @@
 import (
 	// TODO(cnicolaou): remove this dependency in the future. For now this
 	// saves us some code.
-	"github.com/cosmosnicolaou/llog"
+	"github.com/cosnicolaou/llog"
 )
 
 type InfoLog interface {
@@ -19,6 +19,14 @@
 	// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
 	Infof(format string, args ...interface{})
 
+	// InfoDepth acts as Info but uses depth to determine which call frame to log.
+	// A depth of 0 is equivalent to calling Info.
+	InfoDepth(depth int, args ...interface{})
+
+	// InfofDepth acts as Infof but uses depth to determine which call frame to log.
+	// A depth of 0 is equivalent to calling Infof.
+	InfofDepth(depth int, format string, args ...interface{})
+
 	// InfoStack logs the current goroutine's stack if the all parameter
 	// is false, or the stacks of all goroutines if it's true.
 	InfoStack(all bool)
@@ -83,6 +91,14 @@
 	llog.ModuleSpec
 }
 
+// FilepathSpec allows for the setting of specific log levels for specific
+// files matched by a regular expression. The syntax is <re>=3,<re1>=2.
+// It can be set via the FilepathSpec optional parameter to Configure.
+// It implements the flag.Value interface to support command line option parsing.
+type FilepathSpec struct {
+	llog.FilepathSpec
+}
+
 // TraceLocation specifies the location, file:N, which when encountered will
 // cause logging to emit a stack trace.
 // It can be set via the TraceLocation optional parameter to Configure.
@@ -106,6 +122,10 @@
 	// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
 	Error(args ...interface{})
 
+	// ErrorDepth acts as Error but uses depth to determine which call frame to log.
+	// A depth of 0 is equivalent to calling Error.
+	ErrorDepth(depth int, args ...interface{})
+
 	// Errorf logs to the ERROR and INFO logs.
 	// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
 	Errorf(format string, args ...interface{})
@@ -115,6 +135,10 @@
 	// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
 	Fatal(args ...interface{})
 
+	// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
+	// A depth of 0 is equivalent to calling Fatal.
+	FatalDepth(depth int, args ...interface{})
+
 	// Fatalf logs to the FATAL, ERROR and INFO logs,
 	// including a stack trace of all running goroutines, then calls os.Exit(255).
 	// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
@@ -123,6 +147,10 @@
 	// Panic is equivalent to Error() followed by a call to panic().
 	Panic(args ...interface{})
 
+	// PanicDepth acts as Panic but uses depth to determine which call frame to log.
+	// A depth of 0 is equivalent to calling Panic.
+	PanicDepth(depth int, args ...interface{})
+
 	// Panicf is equivalent to Errorf() followed by a call to panic().
 	Panicf(format string, args ...interface{})
 
diff --git a/vlog/opts.go b/vlog/opts.go
index 9e6000d..4d7328b 100644
--- a/vlog/opts.go
+++ b/vlog/opts.go
@@ -37,11 +37,16 @@
 
 // The syntax of the argument is a comma-separated list of pattern=N,
 // where pattern is a literal file name (minus the ".go" suffix) or
-// "glob" pattern and N is a V level. For instance,
-//	-gopher*=3
+// "glob" pattern and N is a V level. For instance, gopher*=3
 // sets the V level to 3 in all Go files whose names begin "gopher".
 func (_ ModuleSpec) LoggingOpt() {}
 
+// The syntax of the argument is a comma-separated list of regexp=N,
+// where pattern is a regular expression matched against the full path name
+// of files and N is a V level. For instance, myco.com/web/.*=3
+// sets the V level to 3 in all Go files whose path names match myco.com/web/.*".
+func (_ FilepathSpec) LoggingOpt() {}
+
 // Log events at or above this severity are logged to standard
 // error as well as to files.
 func (_ StderrThreshold) LoggingOpt() {}