// Log lines have this form:
//         Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
// where the fields are defined as follows:
//         L                A single character, representing the log level (eg 'I' for INFO)
//         mm               The month (zero padded; ie May is '05')
//         dd               The day (zero padded)
//         hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
//         threadid         The space-padded thread ID as returned by GetTID()
//         file             The file name
//         line             The line number
//         msg              The user-supplied message
func (f *GlogFormatter) Format(context log.LogContext) []byte {
	res := &bytes.Buffer{}

	file := context.File
	slash := len(file) - 1
	for ; slash >= 0; slash-- {
		if file[slash] == filepath.Separator {
			break
		}
	}
	if slash >= 0 {
		file = file[slash+1:]
	}

	_, month, day := context.Time.Date()
	hour, minute, second := context.Time.Clock()
	f.tmp[0] = log.UcShortestSeverityStrings[log.SeverityToIndex(context.Severity)][0]
	log.TwoDigits(&f.tmp, 1, int(month))
	log.TwoDigits(&f.tmp, 3, day)
	f.tmp[5] = ' '
	log.TwoDigits(&f.tmp, 6, hour)
	f.tmp[8] = ':'
	log.TwoDigits(&f.tmp, 9, minute)
	f.tmp[11] = ':'
	log.TwoDigits(&f.tmp, 12, second)
	f.tmp[14] = '.'
	log.NDigits(&f.tmp, 6, 15, context.Time.Nanosecond()/1000)
	f.tmp[21] = ' '
	log.NDigits(&f.tmp, 5, 22, context.Pid)
	f.tmp[27] = ' '
	res.Write(f.tmp[:28])
	res.WriteString(file)
	f.tmp[0] = ':'
	n := log.Itoa(&f.tmp, 1, context.Line)
	f.tmp[n+1] = ']'
	f.tmp[n+2] = ' '
	res.Write(f.tmp[:n+3])
	message := ""
	if context.Format != nil {
		message = fmt.Sprintf(*context.Format, context.Args...)
	} else {
		message = fmt.Sprint(context.Args...)
	}

	res.WriteString(message)

	l := len(message)
	if l > 0 && message[l-1] != '\n' {
		res.WriteRune('\n')
	}

	return res.Bytes()
}
// Format formats a LogContext into the GELF format.
func (f *GELFFormatter) Format(context log.LogContext) []byte {
	file := context.File
	if len(file) == 0 {
		file = "???"
	} else {
		slash := len(file) - 1
		for ; slash >= 0; slash-- {
			if file[slash] == filepath.Separator {
				break
			}
		}
		if slash >= 0 {
			file = file[slash+1:]
		}
	}

	e := Extra{
		"_file":     file,
		"_line":     context.Line,
		"_severity": log.LcSeverityStrings[log.SeverityToIndex(context.Severity)],
		"_facility": f.appname + "." + context.Function,
	}

	var args []interface{}
	for _, v := range context.Args {
		switch t := v.(type) {
		case Extra:
			for key, value := range t {
				e[key] = value
			}
		case *http.Request:
			header := make(map[string]interface{})
			// Copy header
			for key, value := range t.Header {
				// Don't copy auth. Don't want this in logs.
				// Note: If you add more auth schemes then you have to update
				// this code to remove those too.
				if strings.EqualFold(key, "authorization") {
					continue
				}

				header[key] = value
			}

			e["_request_method"] = t.Method
			// We have to use RequestURI because URL may be
			// modified by routes.
			e["_request_url"] = t.RequestURI //t.URL.String(),
			e["_request_host"] = t.Host
			e["_request_remote_addr"] = t.RemoteAddr
			e["_request_header"] = header

		default:
			args = append(args, v)
		}
	}

	message := ""
	if context.Format != nil {
		message = fmt.Sprintf(*context.Format, args...)
	} else {
		message = fmt.Sprint(args...)
	}

	gf := gelf{
		Version: "1.1",
		Host:    f.hostname,
		Short:   message,
		//Full:     message,
		TimeUnix: time.Now().Unix(),
		Level:    6, // info
		Extra:    e,
	}

	buf, _ := json.Marshal(&gf)
	buf = append(buf, '\n')

	return buf
}
Beispiel #3
0
//SeverityToString converts the Severity to human readable string
func SeverityToString(s factorlog.Severity) string {
	return factorlog.CapSeverityStrings[factorlog.SeverityToIndex(s)]
}