func V(level Level) Verbose {
	if logging.verbosity.get() >= level {
		return Verbose(true)
	}
	if atomic.LoadInt32(&logging.filterLength) > 0 {
		logging.mu.Lock()
		defer logging.mu.Unlock()
		if runtime.Callers(2, logging.pcs[:]) == 0 {
			return Verbose(false)
		}
		v, ok := logging.vmap[logging.pcs[0]]
		if !ok {
			v = logging.setV(logging.pcs[0])
		}
		return Verbose(v >= level)
	}
	return Verbose(false)
}
V reports whether verbosity at the call site is at least the requested level.
The returned value is a boolean of type Verbose, which implements Info, Infoln
and Infof. These methods will write to the Info log if called.
Thus, one may write either
if glog.V(2) { glog.Info("log this") }
or
glog.V(2).Info("log this")
The second form is shorter but the first is cheaper if logging is off because it does
not evaluate its arguments.

Whether an individual call to V generates a log record depends on the setting of
the -v and --vmodule flags; both are off by default. If the level in the call to
V is at least the value of -v, or of -vmodule for the source file containing the
call, the V call will log.
package glog
import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)
type severity int32  
const (
	infoLog severity = iota
	warningLog
	errorLog
	fatalLog
	numSeverity = 4
)
const severityChar = "IWEF"
var severityName = []string{
	infoLog:    "INFO",
	warningLog: "WARNING",
	errorLog:   "ERROR",
	fatalLog:   "FATAL",
}
func (s *severity) get() severity {
	return severity(atomic.LoadInt32((*int32)(s)))
}
func (s *severity) set(val severity) {
	atomic.StoreInt32((*int32)(s), int32(val))
}
func (s *severity) String() string {
	return strconv.FormatInt(int64(*s), 10)
}
func (s *severity) Get() interface{} {
	return *s
}
func (s *severity) Set(value string) error {
	var threshold severity
	if v, ok := severityByName(value); ok {
		threshold = v
	} else {
		v, err := strconv.Atoi(value)
		if err != nil {
			return err
		}
		threshold = severity(v)
	}
	logging.stderrThreshold.set(threshold)
	return nil
}
func severityByName(s string) (severity, bool) {
	s = strings.ToUpper(s)
	for i, name := range severityName {
		if name == s {
			return severity(i), true
		}
	}
	return 0, false
}
type OutputStats struct {
	lines int64
	bytes int64
}
func (s *OutputStats) Lines() int64 {
	return atomic.LoadInt64(&s.lines)
}
func (s *OutputStats) Bytes() int64 {
	return atomic.LoadInt64(&s.bytes)
}
var Stats struct {
	Info, Warning, Error OutputStats
}
var severityStats = [numSeverity]*OutputStats{
	infoLog:    &Stats.Info,
	warningLog: &Stats.Warning,
	errorLog:   &Stats.Error,
}
type Level int32
func (l *Level) get() Level {
	return Level(atomic.LoadInt32((*int32)(l)))
}
func (l *Level) set(val Level) {
	atomic.StoreInt32((*int32)(l), int32(val))
}
func (l *Level) String() string {
	return strconv.FormatInt(int64(*l), 10)
}
func (l *Level) Get() interface{} {
	return *l
}
func (l *Level) Set(value string) error {
	v, err := strconv.Atoi(value)
	if err != nil {
		return err
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	logging.setVState(Level(v), logging.vmodule.filter, false)
	return nil
}
type moduleSpec struct {
	filter []modulePat
}
type modulePat struct {
	pattern string
	literal bool  
	level   Level
}
func (m *modulePat) match(file string) bool {
	if m.literal {
		return file == m.pattern
	}
	match, _ := filepath.Match(m.pattern, file)
	return match
}
func (m *moduleSpec) String() string {
	logging.mu.Lock()
	defer logging.mu.Unlock()
	var b bytes.Buffer
	for i, f := range m.filter {
		if i > 0 {
			b.WriteRune(',')
		}
		fmt.Fprintf(&b, "%s=%d", f.pattern, f.level)
	}
	return b.String()
}
func (m *moduleSpec) Get() interface{} {
	return nil
}
var errVmoduleSyntax = errors.New("syntax error: expect comma-separated list of filename=N")
func (m *moduleSpec) Set(value string) error {
	var filter []modulePat
	for _, pat := range strings.Split(value, ",") {
		if len(pat) == 0 {
			continue
		}
		patLev := strings.Split(pat, "=")
		if len(patLev) != 2 || len(patLev[0]) == 0 || len(patLev[1]) == 0 {
			return errVmoduleSyntax
		}
		pattern := patLev[0]
		v, err := strconv.Atoi(patLev[1])
		if err != nil {
			return errors.New("syntax error: expect comma-separated list of filename=N")
		}
		if v < 0 {
			return errors.New("negative value for vmodule level")
		}
		if v == 0 {
			continue  
		}
		filter = append(filter, modulePat{pattern, isLiteral(pattern), Level(v)})
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	logging.setVState(logging.verbosity, filter, true)
	return nil
}
func isLiteral(pattern string) bool {
	return !strings.ContainsAny(pattern, `*?[]\`)
}
type traceLocation struct {
	file string
	line int
}
func (t *traceLocation) isSet() bool {
	return t.line > 0
}
func (t *traceLocation) match(file string, line int) bool {
	if t.line != line {
		return false
	}
	if i := strings.LastIndex(file, "/"); i >= 0 {
		file = file[i+1:]
	}
	return t.file == file
}
func (t *traceLocation) String() string {
	logging.mu.Lock()
	defer logging.mu.Unlock()
	return fmt.Sprintf("%s:%d", t.file, t.line)
}
func (t *traceLocation) Get() interface{} {
	return nil
}
var errTraceSyntax = errors.New("syntax error: expect file.go:234")
func (t *traceLocation) Set(value string) error {
	if value == "" {
		t.line = 0
		t.file = ""
	}
	fields := strings.Split(value, ":")
	if len(fields) != 2 {
		return errTraceSyntax
	}
	file, line := fields[0], fields[1]
	if !strings.Contains(file, ".") {
		return errTraceSyntax
	}
	v, err := strconv.Atoi(line)
	if err != nil {
		return errTraceSyntax
	}
	if v <= 0 {
		return errors.New("negative or zero value for level")
	}
	logging.mu.Lock()
	defer logging.mu.Unlock()
	t.line = v
	t.file = file
	return nil
}
type flushSyncWriter interface {
	Flush() error
	Sync() error
	io.Writer
}
func init() {
	flag.BoolVar(&logging.toStderr, "logtostderr", false, "log to standard error instead of files")
	flag.BoolVar(&logging.alsoToStderr, "alsologtostderr", false, "log to standard error as well as files")
	flag.Var(&logging.verbosity, "v", "log level for V logs")
	flag.Var(&logging.stderrThreshold, "stderrthreshold", "logs at or above this threshold go to stderr")
	flag.Var(&logging.vmodule, "vmodule", "comma-separated list of pattern=N settings for file-filtered logging")
	flag.Var(&logging.traceLocation, "log_backtrace_at", "when logging hits line file:N, emit a stack trace")
	logging.stderrThreshold = errorLog
	logging.setVState(0, nil, false)
	go logging.flushDaemon()
}
func Flush() {
	logging.lockAndFlushAll()
}
type loggingT struct {
	toStderr     bool  
	alsoToStderr bool  
	stderrThreshold severity  
	freeList *buffer
	freeListMu sync.Mutex
	mu sync.Mutex
	file [numSeverity]flushSyncWriter
	pcs [1]uintptr
	vmap map[uintptr]Level
	filterLength int32
	traceLocation traceLocation
	vmodule   moduleSpec  
	verbosity Level       
}
type buffer struct {
	bytes.Buffer
	tmp  [64]byte  
	next *buffer
}
var logging loggingT
func (l *loggingT) setVState(verbosity Level, filter []modulePat, setFilter bool) {
	logging.verbosity.set(0)
	logging.filterLength = 0
	if setFilter {
		logging.vmodule.filter = filter
		logging.vmap = make(map[uintptr]Level)
	}
	atomic.StoreInt32(&logging.filterLength, int32(len(filter)))
	logging.verbosity.set(verbosity)
}
func (l *loggingT) getBuffer() *buffer {
	l.freeListMu.Lock()
	b := l.freeList
	if b != nil {
		l.freeList = b.next
	}
	l.freeListMu.Unlock()
	if b == nil {
		b = new(buffer)
	} else {
		b.next = nil
		b.Reset()
	}
	return b
}
func (l *loggingT) putBuffer(b *buffer) {
	if b.Len() >= 256 {
		return
	}
	l.freeListMu.Lock()
	b.next = l.freeList
	l.freeList = b
	l.freeListMu.Unlock()
}
var timeNow = time.Now  
func (l *loggingT) header(s severity) *buffer {
	now := timeNow()
	_, file, line, ok := runtime.Caller(3)  
	if !ok {
		file = "???"
		line = 1
	} else {
		slash := strings.LastIndex(file, "/")
		if slash >= 0 {
			file = file[slash+1:]
		}
	}
	if line < 0 {
		line = 0  
	}
	if s > fatalLog {
		s = infoLog  
	}
	buf := l.getBuffer()
	_, month, day := now.Date()
	hour, minute, second := now.Clock()
	buf.tmp[0] = severityChar[s]
	buf.twoDigits(1, int(month))
	buf.twoDigits(3, day)
	buf.tmp[5] = ' '
	buf.twoDigits(6, hour)
	buf.tmp[8] = ':'
	buf.twoDigits(9, minute)
	buf.tmp[11] = ':'
	buf.twoDigits(12, second)
	buf.tmp[14] = '.'
	buf.nDigits(6, 15, now.Nanosecond()/1000)
	buf.tmp[21] = ' '
	buf.nDigits(5, 22, pid)  
	buf.tmp[27] = ' '
	buf.Write(buf.tmp[:28])
	buf.WriteString(file)
	buf.tmp[0] = ':'
	n := buf.someDigits(1, line)
	buf.tmp[n+1] = ']'
	buf.tmp[n+2] = ' '
	buf.Write(buf.tmp[:n+3])
	return buf
}
const digits = "0123456789"
func (buf *buffer) twoDigits(i, d int) {
	buf.tmp[i+1] = digits[d%10]
	d /= 10
	buf.tmp[i] = digits[d%10]
}
func (buf *buffer) nDigits(n, i, d int) {
	for j := n - 1; j >= 0; j-- {
		buf.tmp[i+j] = digits[d%10]
		d /= 10
	}
}
func (buf *buffer) someDigits(i, d int) int {
	j := len(buf.tmp)
	for {
		j--
		buf.tmp[j] = digits[d%10]
		d /= 10
		if d == 0 {
			break
		}
	}
	return copy(buf.tmp[i:], buf.tmp[j:])
}
func (l *loggingT) println(s severity, args ...interface{}) {
	buf := l.header(s)
	fmt.Fprintln(buf, args...)
	l.output(s, buf)
}
func (l *loggingT) print(s severity, args ...interface{}) {
	buf := l.header(s)
	fmt.Fprint(buf, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf)
}
func (l *loggingT) printf(s severity, format string, args ...interface{}) {
	buf := l.header(s)
	fmt.Fprintf(buf, format, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf)
}
func (l *loggingT) output(s severity, buf *buffer) {
	l.mu.Lock()
	if l.traceLocation.isSet() {
		_, file, line, ok := runtime.Caller(3)  
		if ok && l.traceLocation.match(file, line) {
			buf.Write(stacks(false))
		}
	}
	data := buf.Bytes()
	if l.toStderr {
		os.Stderr.Write(data)
	} else {
		if l.alsoToStderr || s >= l.stderrThreshold.get() {
			os.Stderr.Write(data)
		}
		if l.file[s] == nil {
			if err := l.createFiles(s); err != nil {
				os.Stderr.Write(data)  
				l.exit(err)
			}
		}
		switch s {
		case fatalLog:
			l.file[fatalLog].Write(data)
			fallthrough
		case errorLog:
			l.file[errorLog].Write(data)
			fallthrough
		case warningLog:
			l.file[warningLog].Write(data)
			fallthrough
		case infoLog:
			l.file[infoLog].Write(data)
		}
	}
	if s == fatalLog {
		if !l.toStderr {
			os.Stderr.Write(stacks(false))
		}
		trace := stacks(true)
		logExitFunc = func(error) {}  
		for log := fatalLog; log >= infoLog; log-- {
			if f := l.file[log]; f != nil {  
				f.Write(trace)
			}
		}
		l.mu.Unlock()
		timeoutFlush(10 * time.Second)
		os.Exit(255)  
	}
	l.putBuffer(buf)
	l.mu.Unlock()
	if stats := severityStats[s]; stats != nil {
		atomic.AddInt64(&stats.lines, 1)
		atomic.AddInt64(&stats.bytes, int64(len(data)))
	}
}
func timeoutFlush(timeout time.Duration) {
	done := make(chan bool, 1)
	go func() {
		Flush()  
		done <- true
	}()
	select {
	case <-done:
	case <-time.After(timeout):
		fmt.Fprintln(os.Stderr, "glog: Flush took longer than", timeout)
	}
}
func stacks(all bool) []byte {
	n := 10000
	if all {
		n = 100000
	}
	var trace []byte
	for i := 0; i < 5; i++ {
		trace = make([]byte, n)
		nbytes := runtime.Stack(trace, all)
		if nbytes < len(trace) {
			return trace[:nbytes]
		}
		n *= 2
	}
	return trace
}
var logExitFunc func(error)
func (l *loggingT) exit(err error) {
	fmt.Fprintf(os.Stderr, "log: exiting because of error: %s\n", err)
	if logExitFunc != nil {
		logExitFunc(err)
		return
	}
	l.flushAll()
	os.Exit(2)
}
type syncBuffer struct {
	logger *loggingT
	*bufio.Writer
	file   *os.File
	sev    severity
	nbytes uint64  
}
func (sb *syncBuffer) Sync() error {
	return sb.file.Sync()
}
func (sb *syncBuffer) Write(p []byte) (n int, err error) {
	if sb.nbytes+uint64(len(p)) >= MaxSize {
		if err := sb.rotateFile(time.Now()); err != nil {
			sb.logger.exit(err)
		}
	}
	n, err = sb.Writer.Write(p)
	sb.nbytes += uint64(n)
	if err != nil {
		sb.logger.exit(err)
	}
	return
}
func (sb *syncBuffer) rotateFile(now time.Time) error {
	if sb.file != nil {
		sb.Flush()
		sb.file.Close()
	}
	var err error
	sb.file, _, err = create(severityName[sb.sev], now)
	sb.nbytes = 0
	if err != nil {
		return err
	}
	sb.Writer = bufio.NewWriterSize(sb.file, bufferSize)
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "Log file created at: %s\n", now.Format("2006/01/02 15:04:05"))
	fmt.Fprintf(&buf, "Running on machine: %s\n", host)
	fmt.Fprintf(&buf, "Binary: Built with %s %s for %s/%s\n", runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH)
	fmt.Fprintf(&buf, "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg\n")
	n, err := sb.file.Write(buf.Bytes())
	sb.nbytes += uint64(n)
	return err
}
const bufferSize = 256 * 1024
func (l *loggingT) createFiles(sev severity) error {
	now := time.Now()
	for s := sev; s >= infoLog && l.file[s] == nil; s-- {
		sb := &syncBuffer{
			logger: l,
			sev:    s,
		}
		if err := sb.rotateFile(now); err != nil {
			return err
		}
		l.file[s] = sb
	}
	return nil
}
const flushInterval = 30 * time.Second
func (l *loggingT) flushDaemon() {
	for _ = range time.NewTicker(flushInterval).C {
		l.lockAndFlushAll()
	}
}
func (l *loggingT) lockAndFlushAll() {
	l.mu.Lock()
	l.flushAll()
	l.mu.Unlock()
}
func (l *loggingT) flushAll() {
	for s := fatalLog; s >= infoLog; s-- {
		file := l.file[s]
		if file != nil {
			file.Flush()  
			file.Sync()   
		}
	}
}
func (l *loggingT) setV(pc uintptr) Level {
	fn := runtime.FuncForPC(pc)
	file, _ := fn.FileLine(pc)
	if strings.HasSuffix(file, ".go") {
		file = file[:len(file)-3]
	}
	if slash := strings.LastIndex(file, "/"); slash >= 0 {
		file = file[slash+1:]
	}
	for _, filter := range l.vmodule.filter {
		if filter.match(file) {
			l.vmap[pc] = filter.level
			return filter.level
		}
	}
	l.vmap[pc] = 0
	return 0
}
type Verbose bool