kvlog/writer.go
func (w *logWriter) Write(p []byte) (n int, err error) {
	var (
		now     = time.Now() // do this early
		prefix  string
		logdate []byte
		logtime []byte
		file    []byte
		changed bool
	)

	if w.utc {
		now = now.UTC()
	}
	if w.prefixb != nil {
		if bytes.HasPrefix(p, w.prefixb) {
			prefix = w.prefixs
			p = p[len(prefix):]
		} else {
			changed = true
		}
	}
	p = bytes.TrimLeftFunc(p, isspace)
	if w.dateRE != nil {
		dateb := w.dateRE.Find(p)
		if dateb != nil {
			logdate = dateb
			p = p[len(dateb):]
			p = bytes.TrimLeftFunc(p, isspace)
		} else {
			changed = true
		}
	}
	if w.timeRE != nil {
		timeb := w.timeRE.Find(p)
		if timeb != nil {
			logtime = timeb
			p = p[len(timeb):]
			p = bytes.TrimLeftFunc(p, isspace)
		} else {
			changed = true
		}
	}
	if w.fileRE != nil {
		fileb := w.fileRE.Find(p)
		if fileb != nil {
			file = fileb
			p = p[len(fileb):]
			p = bytes.TrimLeftFunc(p, isspace)
			skip := colonRE.Find(p)
			p = p[len(skip):]
		} else {
			changed = true
		}
	}

	w.output.mutex.Lock()
	if w.output.levels == nil {
		// apply the default levels as late as possible,
		// which gives the calling program an opportunity
		// to change default levels at program initialization
		w.output.setLevels(Levels)
	}
	if !w.output.shouldSuppress(p) {
		level, effect, skip := w.output.getLevel(p)
		p = p[skip:]
		msg := parse.Bytes(p)
		ent := logEntry{
			Timestamp: now,
			Prefix:    prefix,
			Date:      logdate,
			Time:      logtime,
			File:      file,
			Level:     level,
			Effect:    effect,
			Text:      msg.Text,
			List:      msg.List,
		}
		w.output.handler(&ent)
		msg.Release()
	}
	w.output.mutex.Unlock()

	if changed && !w.changed {
		w.changed = true
		go func() {
			w.output.Attach(w.logger)
			if w.logger == nil {
				log.Println("warning: logger details changed after kvlog.Attach")
			} else {
				w.logger.Println("warning: logger details after kvlog.Writer.Attach")
			}
		}()
	}

	return len(p), nil
}
func (w *logWriter) Write(p []byte) (n int, err error) {
	var (
		now     = time.Now() // do this early
		prefix  string
		logdate []byte
		logtime []byte
		file    []byte
		changed bool
	)

	if w.utc {
		now = now.UTC()
	}
	if w.prefixb != nil {
		if bytes.HasPrefix(p, w.prefixb) {
			prefix = w.prefixs
			p = p[len(prefix):]
		} else {
			changed = true
		}
	}
	p = bytes.TrimLeftFunc(p, isspace)
	if w.dateRE != nil {
		dateb := w.dateRE.Find(p)
		if dateb != nil {
			logdate = dateb
			p = p[len(dateb):]
			p = bytes.TrimLeftFunc(p, isspace)
		} else {
			changed = true
		}
	}
	if w.timeRE != nil {
		timeb := w.timeRE.Find(p)
		if timeb != nil {
			logtime = timeb
			p = p[len(timeb):]
			p = bytes.TrimLeftFunc(p, isspace)
		} else {
			changed = true
		}
	}
	if w.fileRE != nil {
		fileb := w.fileRE.Find(p)
		if fileb != nil {
			file = fileb
			p = p[len(fileb):]
			p = bytes.TrimLeftFunc(p, isspace)
			skip := colonRE.Find(p)
			p = p[len(skip):]
		} else {
			changed = true
		}
	}

	w.output.mutex.Lock()
	if w.output.levels == nil {
		// apply the default levels as late as possible,
		// which gives the calling program an opportunity
		// to change default levels at program initialization
		w.output.setLevels(Levels)
	}
	if !w.output.shouldSuppress(p) {
		level, effect, skip := w.output.getLevel(p)
		p = p[skip:]
		msg := parse.Bytes(p)
		ent := logEntry{
			Timestamp: now,
			Prefix:    prefix,
			Date:      logdate,
			Time:      logtime,
			File:      file,
			Level:     level,
			Effect:    effect,
			Text:      msg.Text,
			List:      msg.List,
		}
		w.output.handler(&ent)
		msg.Release()
	}
	w.output.mutex.Unlock()

	if changed && !w.changed {
		w.changed = true
		go func() {
			w.output.Attach(w.logger)
			if w.logger == nil {
				log.Println("warning: logger details changed after kvlog.Attach")
			} else {
				w.logger.Println("warning: logger details after kvlog.Writer.Attach")
			}
		}()
	}

	return len(p), nil
}
func ( w * logWriter ) Write ( p [ ] byte ) ( n int , err error ) { var ( now = time . Now ( ) // do this early prefix string logdate [ ] byte logtime [ ] byte file [ ] byte changed bool ) if w . utc { now = now . UTC ( ) } if w . prefixb != nil { if bytes . HasPrefix ( p , w . prefixb ) { prefix = w . prefixs p = p [ len ( prefix ) : ] } else { changed = true } } p = bytes . TrimLeftFunc ( p , isspace ) if w . dateRE != nil { dateb := w . dateRE . Find ( p ) if dateb != nil { logdate = dateb p = p [ len ( dateb ) : ] p = bytes . TrimLeftFunc ( p , isspace ) } else { changed = true } } if w . timeRE != nil { timeb := w . timeRE . Find ( p ) if timeb != nil { logtime = timeb p = p [ len ( timeb ) : ] p = bytes . TrimLeftFunc ( p , isspace ) } else { changed = true } } if w . fileRE != nil { fileb := w . fileRE . Find ( p ) if fileb != nil { file = fileb p = p [ len ( fileb ) : ] p = bytes . TrimLeftFunc ( p , isspace ) skip := colonRE . Find ( p ) p = p [ len ( skip ) : ] } else { changed = true } } w . output . mutex . Lock ( ) if w . output . levels == nil { // apply the default levels as late as possible, // which gives the calling program an opportunity // to change default levels at program initialization w . output . setLevels ( Levels ) } if ! w . output . shouldSuppress ( p ) { level , effect , skip := w . output . getLevel ( p ) p = p [ skip : ] msg := parse . Bytes ( p ) ent := logEntry { Timestamp : now , Prefix : prefix , Date : logdate , Time : logtime , File : file , Level : level , Effect : effect , Text : msg . Text , List : msg . List , } w . output . handler ( & ent ) msg . Release ( ) } w . output . mutex . Unlock ( ) if changed && ! w . changed { w . changed = true go func ( ) { w . output . Attach ( w . logger ) if w . logger == nil { log . Println ( " " ) } else { w . logger . Println ( " " ) } } ( ) } return len ( p ) , nil }
// Write implements the io.Writer interface. This method is
// called from the logger. Because the logger's mutex is
// locked, and because we want to read the logger's prefix and
// its flags, we copy the details and let the actual logging
// be done by a goroutine.
Write implements the io . Writer interface . This method is called from the logger . Because the logger s mutex is locked and because we want to read the logger s prefix and its flags we copy the details and let the actual logging be done by a goroutine .