Merge pull request #3036 from jhowardmsft/jjh/etw
Windows: Enable ETW logging
This commit is contained in:
commit
dea27b1b64
@ -24,6 +24,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
winio "github.com/Microsoft/go-winio"
|
winio "github.com/Microsoft/go-winio"
|
||||||
|
"github.com/Microsoft/go-winio/pkg/etwlogrus"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/containerd/containerd/services/server"
|
"github.com/containerd/containerd/services/server"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -89,3 +90,12 @@ func setupDumpStacks() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Provider ID: {2acb92c0-eb9b-571a-69cf-8f3410f383ad}
|
||||||
|
// Hook isn't closed explicitly, as it will exist until process exit.
|
||||||
|
// GUID is generated based on name - see Microsoft/go-winio/tools/etw-provider-gen.
|
||||||
|
if hook, err := etwlogrus.NewHook("ContainerD"); err == nil {
|
||||||
|
logrus.AddHook(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,7 +21,8 @@ github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
|
|||||||
github.com/golang/protobuf v1.1.0
|
github.com/golang/protobuf v1.1.0
|
||||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
||||||
github.com/opencontainers/runc 6635b4f0c6af3810594d2770f662f34ddc15b40d
|
github.com/opencontainers/runc 6635b4f0c6af3810594d2770f662f34ddc15b40d
|
||||||
github.com/sirupsen/logrus v1.0.3
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||||
|
github.com/sirupsen/logrus v1.3.0
|
||||||
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
||||||
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||||
google.golang.org/grpc v1.12.0
|
google.golang.org/grpc v1.12.0
|
||||||
@ -32,7 +33,7 @@ github.com/opencontainers/image-spec v1.0.1
|
|||||||
golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
|
golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
|
||||||
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||||
github.com/Microsoft/go-winio v0.4.11
|
github.com/Microsoft/go-winio v0.4.12
|
||||||
github.com/Microsoft/hcsshim v0.8.5
|
github.com/Microsoft/hcsshim v0.8.5
|
||||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||||
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
||||||
|
15
vendor/github.com/Microsoft/go-winio/internal/etw/etw.go
generated
vendored
Normal file
15
vendor/github.com/Microsoft/go-winio/internal/etw/etw.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Package etw provides support for TraceLogging-based ETW (Event Tracing
|
||||||
|
// for Windows). TraceLogging is a format of ETW events that are self-describing
|
||||||
|
// (the event contains information on its own schema). This allows them to be
|
||||||
|
// decoded without needing a separate manifest with event information. The
|
||||||
|
// implementation here is based on the information found in
|
||||||
|
// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
|
||||||
|
// set of C macros.
|
||||||
|
package etw
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
|
||||||
|
|
||||||
|
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
|
||||||
|
//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
|
||||||
|
//sys eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
|
||||||
|
//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
|
65
vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go
generated
vendored
Normal file
65
vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventData maintains a buffer which builds up the data for an ETW event. It
|
||||||
|
// needs to be paired with EventMetadata which describes the event.
|
||||||
|
type EventData struct {
|
||||||
|
buffer bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the raw binary data containing the event data. The returned
|
||||||
|
// value is not copied from the internal buffer, so it can be mutated by the
|
||||||
|
// EventData object after it is returned.
|
||||||
|
func (ed *EventData) Bytes() []byte {
|
||||||
|
return ed.buffer.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteString appends a string, including the null terminator, to the buffer.
|
||||||
|
func (ed *EventData) WriteString(data string) {
|
||||||
|
ed.buffer.WriteString(data)
|
||||||
|
ed.buffer.WriteByte(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteInt8 appends a int8 to the buffer.
|
||||||
|
func (ed *EventData) WriteInt8(value int8) {
|
||||||
|
ed.buffer.WriteByte(uint8(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteInt16 appends a int16 to the buffer.
|
||||||
|
func (ed *EventData) WriteInt16(value int16) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteInt32 appends a int32 to the buffer.
|
||||||
|
func (ed *EventData) WriteInt32(value int32) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteInt64 appends a int64 to the buffer.
|
||||||
|
func (ed *EventData) WriteInt64(value int64) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteUint8 appends a uint8 to the buffer.
|
||||||
|
func (ed *EventData) WriteUint8(value uint8) {
|
||||||
|
ed.buffer.WriteByte(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteUint16 appends a uint16 to the buffer.
|
||||||
|
func (ed *EventData) WriteUint16(value uint16) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteUint32 appends a uint32 to the buffer.
|
||||||
|
func (ed *EventData) WriteUint32(value uint32) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteUint64 appends a uint64 to the buffer.
|
||||||
|
func (ed *EventData) WriteUint64(value uint64) {
|
||||||
|
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||||
|
}
|
29
vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go
generated
vendored
Normal file
29
vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventDataDescriptorType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventDataDescriptorTypeUserData eventDataDescriptorType = iota
|
||||||
|
eventDataDescriptorTypeEventMetadata
|
||||||
|
eventDataDescriptorTypeProviderMetadata
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventDataDescriptor struct {
|
||||||
|
ptr ptr64
|
||||||
|
size uint32
|
||||||
|
dataType eventDataDescriptorType
|
||||||
|
reserved1 uint8
|
||||||
|
reserved2 uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
|
||||||
|
return eventDataDescriptor{
|
||||||
|
ptr: ptr64{ptr: unsafe.Pointer(&buffer[0])},
|
||||||
|
size: uint32(len(buffer)),
|
||||||
|
dataType: dataType,
|
||||||
|
}
|
||||||
|
}
|
67
vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go
generated
vendored
Normal file
67
vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
// Channel represents the ETW logging channel that is used. It can be used by
|
||||||
|
// event consumers to give an event special treatment.
|
||||||
|
type Channel uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ChannelTraceLogging is the default channel for TraceLogging events. It is
|
||||||
|
// not required to be used for TraceLogging, but will prevent decoding
|
||||||
|
// issues for these events on older operating systems.
|
||||||
|
ChannelTraceLogging Channel = 11
|
||||||
|
)
|
||||||
|
|
||||||
|
// Level represents the ETW logging level. There are several predefined levels
|
||||||
|
// that are commonly used, but technically anything from 0-255 is allowed.
|
||||||
|
// Lower levels indicate more important events, and 0 indicates an event that
|
||||||
|
// will always be collected.
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
// Predefined ETW log levels.
|
||||||
|
const (
|
||||||
|
LevelAlways Level = iota
|
||||||
|
LevelCritical
|
||||||
|
LevelError
|
||||||
|
LevelWarning
|
||||||
|
LevelInfo
|
||||||
|
LevelVerbose
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventDescriptor represents various metadata for an ETW event.
|
||||||
|
type EventDescriptor struct {
|
||||||
|
id uint16
|
||||||
|
version uint8
|
||||||
|
Channel Channel
|
||||||
|
Level Level
|
||||||
|
Opcode uint8
|
||||||
|
Task uint16
|
||||||
|
Keyword uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventDescriptor returns an EventDescriptor initialized for use with
|
||||||
|
// TraceLogging.
|
||||||
|
func NewEventDescriptor() *EventDescriptor {
|
||||||
|
// Standard TraceLogging events default to the TraceLogging channel, and
|
||||||
|
// verbose level.
|
||||||
|
return &EventDescriptor{
|
||||||
|
Channel: ChannelTraceLogging,
|
||||||
|
Level: LevelVerbose,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identity returns the identity of the event. If the identity is not 0, it
|
||||||
|
// should uniquely identify the other event metadata (contained in
|
||||||
|
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||||
|
// are relevant.
|
||||||
|
func (ed *EventDescriptor) Identity() uint32 {
|
||||||
|
return (uint32(ed.version) << 16) | uint32(ed.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIdentity sets the identity of the event. If the identity is not 0, it
|
||||||
|
// should uniquely identify the other event metadata (contained in
|
||||||
|
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||||
|
// are relevant.
|
||||||
|
func (ed *EventDescriptor) SetIdentity(identity uint32) {
|
||||||
|
ed.id = uint16(identity)
|
||||||
|
ed.version = uint8(identity >> 16)
|
||||||
|
}
|
177
vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go
generated
vendored
Normal file
177
vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InType indicates the type of data contained in the ETW event.
|
||||||
|
type InType byte
|
||||||
|
|
||||||
|
// Various InType definitions for TraceLogging. These must match the definitions
|
||||||
|
// found in TraceLoggingProvider.h in the Windows SDK.
|
||||||
|
const (
|
||||||
|
InTypeNull InType = iota
|
||||||
|
InTypeUnicodeString
|
||||||
|
InTypeANSIString
|
||||||
|
InTypeInt8
|
||||||
|
InTypeUint8
|
||||||
|
InTypeInt16
|
||||||
|
InTypeUint16
|
||||||
|
InTypeInt32
|
||||||
|
InTypeUint32
|
||||||
|
InTypeInt64
|
||||||
|
InTypeUint64
|
||||||
|
InTypeFloat
|
||||||
|
InTypeDouble
|
||||||
|
InTypeBool32
|
||||||
|
InTypeBinary
|
||||||
|
InTypeGUID
|
||||||
|
InTypePointerUnsupported
|
||||||
|
InTypeFileTime
|
||||||
|
InTypeSystemTime
|
||||||
|
InTypeSID
|
||||||
|
InTypeHexInt32
|
||||||
|
InTypeHexInt64
|
||||||
|
InTypeCountedString
|
||||||
|
InTypeCountedANSIString
|
||||||
|
InTypeStruct
|
||||||
|
InTypeCountedBinary
|
||||||
|
InTypeCountedArray InType = 32
|
||||||
|
InTypeArray InType = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
// OutType specifies a hint to the event decoder for how the value should be
|
||||||
|
// formatted.
|
||||||
|
type OutType byte
|
||||||
|
|
||||||
|
// Various OutType definitions for TraceLogging. These must match the
|
||||||
|
// definitions found in TraceLoggingProvider.h in the Windows SDK.
|
||||||
|
const (
|
||||||
|
// OutTypeDefault indicates that the default formatting for the InType will
|
||||||
|
// be used by the event decoder.
|
||||||
|
OutTypeDefault OutType = iota
|
||||||
|
OutTypeNoPrint
|
||||||
|
OutTypeString
|
||||||
|
OutTypeBoolean
|
||||||
|
OutTypeHex
|
||||||
|
OutTypePID
|
||||||
|
OutTypeTID
|
||||||
|
OutTypePort
|
||||||
|
OutTypeIPv4
|
||||||
|
OutTypeIPv6
|
||||||
|
OutTypeSocketAddress
|
||||||
|
OutTypeXML
|
||||||
|
OutTypeJSON
|
||||||
|
OutTypeWin32Error
|
||||||
|
OutTypeNTStatus
|
||||||
|
OutTypeHResult
|
||||||
|
OutTypeFileTime
|
||||||
|
OutTypeSigned
|
||||||
|
OutTypeUnsigned
|
||||||
|
OutTypeUTF8 OutType = 35
|
||||||
|
OutTypePKCS7WithTypeInfo OutType = 36
|
||||||
|
OutTypeCodePointer OutType = 37
|
||||||
|
OutTypeDateTimeUTC OutType = 38
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventMetadata maintains a buffer which builds up the metadata for an ETW
|
||||||
|
// event. It needs to be paired with EventData which describes the event.
|
||||||
|
type EventMetadata struct {
|
||||||
|
buffer bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the raw binary data containing the event metadata. Before being
|
||||||
|
// returned, the current size of the buffer is written to the start of the
|
||||||
|
// buffer. The returned value is not copied from the internal buffer, so it can
|
||||||
|
// be mutated by the EventMetadata object after it is returned.
|
||||||
|
func (em *EventMetadata) Bytes() []byte {
|
||||||
|
// Finalize the event metadata buffer by filling in the buffer length at the
|
||||||
|
// beginning.
|
||||||
|
binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
|
||||||
|
return em.buffer.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteEventHeader writes the metadata for the start of an event to the buffer.
|
||||||
|
// This specifies the event name and tags.
|
||||||
|
func (em *EventMetadata) WriteEventHeader(name string, tags uint32) {
|
||||||
|
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||||
|
em.writeTags(tags)
|
||||||
|
em.buffer.WriteString(name)
|
||||||
|
em.buffer.WriteByte(0) // Null terminator for name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (em *EventMetadata) writeField(name string, inType InType, outType OutType, tags uint32, arrSize uint16) {
|
||||||
|
em.buffer.WriteString(name)
|
||||||
|
em.buffer.WriteByte(0) // Null terminator for name
|
||||||
|
|
||||||
|
if outType == OutTypeDefault && tags == 0 {
|
||||||
|
em.buffer.WriteByte(byte(inType))
|
||||||
|
} else {
|
||||||
|
em.buffer.WriteByte(byte(inType | 128))
|
||||||
|
if tags == 0 {
|
||||||
|
em.buffer.WriteByte(byte(outType))
|
||||||
|
} else {
|
||||||
|
em.buffer.WriteByte(byte(outType | 128))
|
||||||
|
em.writeTags(tags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if arrSize != 0 {
|
||||||
|
binary.Write(&em.buffer, binary.LittleEndian, arrSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeTags writes out the tags value to the event metadata. Tags is a 28-bit
|
||||||
|
// value, interpreted as bit flags, which are only relevant to the event
|
||||||
|
// consumer. The event consumer may choose to attribute special meaning to tags
|
||||||
|
// (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
|
||||||
|
// bytes, each containing 7 bits of tag value, with the high bit set if there is
|
||||||
|
// more tag data in the following byte. This allows for a more compact
|
||||||
|
// representation when not all of the tag bits are needed.
|
||||||
|
func (em *EventMetadata) writeTags(tags uint32) {
|
||||||
|
// Only use the top 28 bits of the tags value.
|
||||||
|
tags &= 0xfffffff
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Tags are written with the most significant bits (e.g. 21-27) first.
|
||||||
|
val := tags >> 21
|
||||||
|
|
||||||
|
if tags&0x1fffff == 0 {
|
||||||
|
// If there is no more data to write after this, write this value
|
||||||
|
// without the high bit set, and return.
|
||||||
|
em.buffer.WriteByte(byte(val & 0x7f))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
em.buffer.WriteByte(byte(val | 0x80))
|
||||||
|
|
||||||
|
tags <<= 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteField writes the metadata for a simple field to the buffer.
|
||||||
|
func (em *EventMetadata) WriteField(name string, inType InType, outType OutType, tags uint32) {
|
||||||
|
em.writeField(name, inType, outType, tags, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteArray writes the metadata for an array field to the buffer. The number
|
||||||
|
// of elements in the array must be written as a uint16 in the event data,
|
||||||
|
// immediately preceeding the event data.
|
||||||
|
func (em *EventMetadata) WriteArray(name string, inType InType, outType OutType, tags uint32) {
|
||||||
|
em.writeField(name, inType|InTypeArray, outType, tags, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteCountedArray writes the metadata for an array field to the buffer. The
|
||||||
|
// size of a counted array is fixed, and the size is written into the metadata
|
||||||
|
// directly.
|
||||||
|
func (em *EventMetadata) WriteCountedArray(name string, count uint16, inType InType, outType OutType, tags uint32) {
|
||||||
|
em.writeField(name, inType|InTypeCountedArray, outType, tags, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteStruct writes the metadata for a nested struct to the buffer. The struct
|
||||||
|
// contains the next N fields in the metadata, where N is specified by the
|
||||||
|
// fieldCount argument.
|
||||||
|
func (em *EventMetadata) WriteStruct(name string, fieldCount uint8, tags uint32) {
|
||||||
|
em.writeField(name, InTypeStruct, OutType(fieldCount), tags, 0)
|
||||||
|
}
|
63
vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go
generated
vendored
Normal file
63
vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventOptions struct {
|
||||||
|
descriptor *EventDescriptor
|
||||||
|
activityID *windows.GUID
|
||||||
|
relatedActivityID *windows.GUID
|
||||||
|
tags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventOpt defines the option function type that can be passed to
|
||||||
|
// Provider.WriteEvent to specify general event options, such as level and
|
||||||
|
// keyword.
|
||||||
|
type EventOpt func(options *eventOptions)
|
||||||
|
|
||||||
|
// WithEventOpts returns the variadic arguments as a single slice.
|
||||||
|
func WithEventOpts(opts ...EventOpt) []EventOpt {
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLevel specifies the level of the event to be written.
|
||||||
|
func WithLevel(level Level) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.descriptor.Level = level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithKeyword specifies the keywords of the event to be written. Multiple uses
|
||||||
|
// of this option are OR'd together.
|
||||||
|
func WithKeyword(keyword uint64) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.descriptor.Keyword |= keyword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithChannel(channel Channel) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.descriptor.Channel = channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTags specifies the tags of the event to be written. Tags is a 28-bit
|
||||||
|
// value (top 4 bits are ignored) which are interpreted by the event consumer.
|
||||||
|
func WithTags(newTags uint32) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.tags |= newTags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithActivityID(activityID *windows.GUID) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.activityID = activityID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithRelatedActivityID(activityID *windows.GUID) EventOpt {
|
||||||
|
return func(options *eventOptions) {
|
||||||
|
options.relatedActivityID = activityID
|
||||||
|
}
|
||||||
|
}
|
379
vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go
generated
vendored
Normal file
379
vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go
generated
vendored
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FieldOpt defines the option function type that can be passed to
|
||||||
|
// Provider.WriteEvent to add fields to the event.
|
||||||
|
type FieldOpt func(em *EventMetadata, ed *EventData)
|
||||||
|
|
||||||
|
// WithFields returns the variadic arguments as a single slice.
|
||||||
|
func WithFields(opts ...FieldOpt) []FieldOpt {
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolField adds a single bool field to the event.
|
||||||
|
func BoolField(name string, value bool) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeUint8, OutTypeBoolean, 0)
|
||||||
|
bool8 := uint8(0)
|
||||||
|
if value {
|
||||||
|
bool8 = uint8(1)
|
||||||
|
}
|
||||||
|
ed.WriteUint8(bool8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolArray adds an array of bool to the event.
|
||||||
|
func BoolArray(name string, values []bool) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
bool8 := uint8(0)
|
||||||
|
if v {
|
||||||
|
bool8 = uint8(1)
|
||||||
|
}
|
||||||
|
ed.WriteUint8(bool8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringField adds a single string field to the event.
|
||||||
|
func StringField(name string, value string) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0)
|
||||||
|
ed.WriteString(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringArray adds an array of string to the event.
|
||||||
|
func StringArray(name string, values []string) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntField adds a single int field to the event.
|
||||||
|
func IntField(name string, value int) FieldOpt {
|
||||||
|
switch unsafe.Sizeof(value) {
|
||||||
|
case 4:
|
||||||
|
return Int32Field(name, int32(value))
|
||||||
|
case 8:
|
||||||
|
return Int64Field(name, int64(value))
|
||||||
|
default:
|
||||||
|
panic("Unsupported int size")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntArray adds an array of int to the event.
|
||||||
|
func IntArray(name string, values []int) FieldOpt {
|
||||||
|
inType := InTypeNull
|
||||||
|
var writeItem func(*EventData, int)
|
||||||
|
switch unsafe.Sizeof(values[0]) {
|
||||||
|
case 4:
|
||||||
|
inType = InTypeInt32
|
||||||
|
writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) }
|
||||||
|
case 8:
|
||||||
|
inType = InTypeInt64
|
||||||
|
writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) }
|
||||||
|
default:
|
||||||
|
panic("Unsupported int size")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
writeItem(ed, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Field adds a single int8 field to the event.
|
||||||
|
func Int8Field(name string, value int8) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeInt8, OutTypeDefault, 0)
|
||||||
|
ed.WriteInt8(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int8Array adds an array of int8 to the event.
|
||||||
|
func Int8Array(name string, values []int8) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeInt8, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteInt8(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Field adds a single int16 field to the event.
|
||||||
|
func Int16Field(name string, value int16) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeInt16, OutTypeDefault, 0)
|
||||||
|
ed.WriteInt16(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16Array adds an array of int16 to the event.
|
||||||
|
func Int16Array(name string, values []int16) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeInt16, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteInt16(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Field adds a single int32 field to the event.
|
||||||
|
func Int32Field(name string, value int32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeInt32, OutTypeDefault, 0)
|
||||||
|
ed.WriteInt32(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Array adds an array of int32 to the event.
|
||||||
|
func Int32Array(name string, values []int32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeInt32, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteInt32(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Field adds a single int64 field to the event.
|
||||||
|
func Int64Field(name string, value int64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeInt64, OutTypeDefault, 0)
|
||||||
|
ed.WriteInt64(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Array adds an array of int64 to the event.
|
||||||
|
func Int64Array(name string, values []int64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeInt64, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteInt64(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintField adds a single uint field to the event.
|
||||||
|
func UintField(name string, value uint) FieldOpt {
|
||||||
|
switch unsafe.Sizeof(value) {
|
||||||
|
case 4:
|
||||||
|
return Uint32Field(name, uint32(value))
|
||||||
|
case 8:
|
||||||
|
return Uint64Field(name, uint64(value))
|
||||||
|
default:
|
||||||
|
panic("Unsupported uint size")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintArray adds an array of uint to the event.
|
||||||
|
func UintArray(name string, values []uint) FieldOpt {
|
||||||
|
inType := InTypeNull
|
||||||
|
var writeItem func(*EventData, uint)
|
||||||
|
switch unsafe.Sizeof(values[0]) {
|
||||||
|
case 4:
|
||||||
|
inType = InTypeUint32
|
||||||
|
writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) }
|
||||||
|
case 8:
|
||||||
|
inType = InTypeUint64
|
||||||
|
writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) }
|
||||||
|
default:
|
||||||
|
panic("Unsupported uint size")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
writeItem(ed, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Field adds a single uint8 field to the event.
|
||||||
|
func Uint8Field(name string, value uint8) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeUint8, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint8(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8Array adds an array of uint8 to the event.
|
||||||
|
func Uint8Array(name string, values []uint8) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeUint8, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint8(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Field adds a single uint16 field to the event.
|
||||||
|
func Uint16Field(name string, value uint16) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeUint16, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint16Array adds an array of uint16 to the event.
|
||||||
|
func Uint16Array(name string, values []uint16) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeUint16, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint16(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Field adds a single uint32 field to the event.
|
||||||
|
func Uint32Field(name string, value uint32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeUint32, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint32(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32Array adds an array of uint32 to the event.
|
||||||
|
func Uint32Array(name string, values []uint32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeUint32, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint32(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Field adds a single uint64 field to the event.
|
||||||
|
func Uint64Field(name string, value uint64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeUint64, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint64(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Array adds an array of uint64 to the event.
|
||||||
|
func Uint64Array(name string, values []uint64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeUint64, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint64(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintptrField adds a single uintptr field to the event.
|
||||||
|
func UintptrField(name string, value uintptr) FieldOpt {
|
||||||
|
inType := InTypeNull
|
||||||
|
var writeItem func(*EventData, uintptr)
|
||||||
|
switch unsafe.Sizeof(value) {
|
||||||
|
case 4:
|
||||||
|
inType = InTypeHexInt32
|
||||||
|
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
|
||||||
|
case 8:
|
||||||
|
inType = InTypeHexInt64
|
||||||
|
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
|
||||||
|
default:
|
||||||
|
panic("Unsupported uintptr size")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, inType, OutTypeDefault, 0)
|
||||||
|
writeItem(ed, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintptrArray adds an array of uintptr to the event.
|
||||||
|
func UintptrArray(name string, values []uintptr) FieldOpt {
|
||||||
|
inType := InTypeNull
|
||||||
|
var writeItem func(*EventData, uintptr)
|
||||||
|
switch unsafe.Sizeof(values[0]) {
|
||||||
|
case 4:
|
||||||
|
inType = InTypeHexInt32
|
||||||
|
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
|
||||||
|
case 8:
|
||||||
|
inType = InTypeHexInt64
|
||||||
|
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
|
||||||
|
default:
|
||||||
|
panic("Unsupported uintptr size")
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
writeItem(ed, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Field adds a single float32 field to the event.
|
||||||
|
func Float32Field(name string, value float32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeFloat, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint32(math.Float32bits(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Array adds an array of float32 to the event.
|
||||||
|
func Float32Array(name string, values []float32) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeFloat, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint32(math.Float32bits(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Field adds a single float64 field to the event.
|
||||||
|
func Float64Field(name string, value float64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteField(name, InTypeDouble, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint64(math.Float64bits(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Array adds an array of float64 to the event.
|
||||||
|
func Float64Array(name string, values []float64) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteArray(name, InTypeDouble, OutTypeDefault, 0)
|
||||||
|
ed.WriteUint16(uint16(len(values)))
|
||||||
|
for _, v := range values {
|
||||||
|
ed.WriteUint64(math.Float64bits(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct adds a nested struct to the event, the FieldOpts in the opts argument
|
||||||
|
// are used to specify the fields of the struct.
|
||||||
|
func Struct(name string, opts ...FieldOpt) FieldOpt {
|
||||||
|
return func(em *EventMetadata, ed *EventData) {
|
||||||
|
em.WriteStruct(name, uint8(len(opts)), 0)
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(em, ed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
279
vendor/github.com/Microsoft/go-winio/internal/etw/provider.go
generated
vendored
Normal file
279
vendor/github.com/Microsoft/go-winio/internal/etw/provider.go
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider represents an ETW event provider. It is identified by a provider
|
||||||
|
// name and ID (GUID), which should always have a 1:1 mapping to each other
|
||||||
|
// (e.g. don't use multiple provider names with the same ID, or vice versa).
|
||||||
|
type Provider struct {
|
||||||
|
ID *windows.GUID
|
||||||
|
handle providerHandle
|
||||||
|
metadata []byte
|
||||||
|
callback EnableCallback
|
||||||
|
index uint
|
||||||
|
enabled bool
|
||||||
|
level Level
|
||||||
|
keywordAny uint64
|
||||||
|
keywordAll uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the `provider`.ID as a string
|
||||||
|
func (provider *Provider) String() string {
|
||||||
|
data1 := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(data1, provider.ID.Data1)
|
||||||
|
data2 := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(data2, provider.ID.Data2)
|
||||||
|
data3 := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(data3, provider.ID.Data3)
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s-%s-%s-%s-%s",
|
||||||
|
hex.EncodeToString(data1),
|
||||||
|
hex.EncodeToString(data2),
|
||||||
|
hex.EncodeToString(data3),
|
||||||
|
hex.EncodeToString(provider.ID.Data4[:2]),
|
||||||
|
hex.EncodeToString(provider.ID.Data4[2:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
type providerHandle windows.Handle
|
||||||
|
|
||||||
|
// ProviderState informs the provider EnableCallback what action is being
|
||||||
|
// performed.
|
||||||
|
type ProviderState uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ProviderStateDisable indicates the provider is being disabled.
|
||||||
|
ProviderStateDisable ProviderState = iota
|
||||||
|
// ProviderStateEnable indicates the provider is being enabled.
|
||||||
|
ProviderStateEnable
|
||||||
|
// ProviderStateCaptureState indicates the provider is having its current
|
||||||
|
// state snap-shotted.
|
||||||
|
ProviderStateCaptureState
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventInfoClass uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
|
||||||
|
eventInfoClassProviderSetReserved1
|
||||||
|
eventInfoClassProviderSetTraits
|
||||||
|
eventInfoClassProviderUseDescriptorType
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnableCallback is the form of the callback function that receives provider
|
||||||
|
// enable/disable notifications from ETW.
|
||||||
|
type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
|
||||||
|
|
||||||
|
func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
|
||||||
|
provider := providers.getProvider(uint(i))
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case ProviderStateDisable:
|
||||||
|
provider.enabled = false
|
||||||
|
case ProviderStateEnable:
|
||||||
|
provider.enabled = true
|
||||||
|
provider.level = level
|
||||||
|
provider.keywordAny = matchAnyKeyword
|
||||||
|
provider.keywordAll = matchAllKeyword
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.callback != nil {
|
||||||
|
provider.callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// providerCallbackAdapter acts as the first-level callback from the C/ETW side
|
||||||
|
// for provider notifications. Because Go has trouble with callback arguments of
|
||||||
|
// different size, it has only pointer-sized arguments, which are then cast to
|
||||||
|
// the appropriate types when calling providerCallback.
|
||||||
|
func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
|
||||||
|
providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// providerIDFromName generates a provider ID based on the provider name. It
|
||||||
|
// uses the same algorithm as used by .NET's EventSource class, which is based
|
||||||
|
// on RFC 4122. More information on the algorithm can be found here:
|
||||||
|
// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/
|
||||||
|
// The algorithm is roughly:
|
||||||
|
// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
|
||||||
|
// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
|
||||||
|
func providerIDFromName(name string) *windows.GUID {
|
||||||
|
buffer := sha1.New()
|
||||||
|
|
||||||
|
namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
|
||||||
|
buffer.Write(namespace)
|
||||||
|
|
||||||
|
binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
|
||||||
|
|
||||||
|
sum := buffer.Sum(nil)
|
||||||
|
sum[7] = (sum[7] & 0xf) | 0x50
|
||||||
|
|
||||||
|
return &windows.GUID{
|
||||||
|
Data1: binary.LittleEndian.Uint32(sum[0:4]),
|
||||||
|
Data2: binary.LittleEndian.Uint16(sum[4:6]),
|
||||||
|
Data3: binary.LittleEndian.Uint16(sum[6:8]),
|
||||||
|
Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider creates and registers a new ETW provider. The provider ID is
|
||||||
|
// generated based on the provider name.
|
||||||
|
func NewProvider(name string, callback EnableCallback) (provider *Provider, err error) {
|
||||||
|
return NewProviderWithID(name, providerIDFromName(name), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProviderWithID creates and registers a new ETW provider, allowing the
|
||||||
|
// provider ID to be manually specified. This is most useful when there is an
|
||||||
|
// existing provider ID that must be used to conform to existing diagnostic
|
||||||
|
// infrastructure.
|
||||||
|
func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) {
|
||||||
|
providerCallbackOnce.Do(func() {
|
||||||
|
globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
|
||||||
|
})
|
||||||
|
|
||||||
|
provider = providers.newProvider()
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
providers.removeProvider(provider)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
provider.ID = id
|
||||||
|
provider.callback = callback
|
||||||
|
|
||||||
|
if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata := &bytes.Buffer{}
|
||||||
|
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||||
|
metadata.WriteString(name)
|
||||||
|
metadata.WriteByte(0) // Null terminator for name
|
||||||
|
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
||||||
|
provider.metadata = metadata.Bytes()
|
||||||
|
|
||||||
|
if err := eventSetInformation(
|
||||||
|
provider.handle,
|
||||||
|
eventInfoClassProviderSetTraits,
|
||||||
|
uintptr(unsafe.Pointer(&provider.metadata[0])),
|
||||||
|
uint32(len(provider.metadata))); err != nil {
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close unregisters the provider.
|
||||||
|
func (provider *Provider) Close() error {
|
||||||
|
providers.removeProvider(provider)
|
||||||
|
return eventUnregister(provider.handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabled calls IsEnabledForLevelAndKeywords with LevelAlways and all
|
||||||
|
// keywords set.
|
||||||
|
func (provider *Provider) IsEnabled() bool {
|
||||||
|
return provider.IsEnabledForLevelAndKeywords(LevelAlways, ^uint64(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabledForLevel calls IsEnabledForLevelAndKeywords with the specified level
|
||||||
|
// and all keywords set.
|
||||||
|
func (provider *Provider) IsEnabledForLevel(level Level) bool {
|
||||||
|
return provider.IsEnabledForLevelAndKeywords(level, ^uint64(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabledForLevelAndKeywords allows event producer code to check if there are
|
||||||
|
// any event sessions that are interested in an event, based on the event level
|
||||||
|
// and keywords. Although this check happens automatically in the ETW
|
||||||
|
// infrastructure, it can be useful to check if an event will actually be
|
||||||
|
// consumed before doing expensive work to build the event data.
|
||||||
|
func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
|
||||||
|
if !provider.enabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ETW automatically sets the level to 255 if it is specified as 0, so we
|
||||||
|
// don't need to worry about the level=0 (all events) case.
|
||||||
|
if level > provider.level {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if keywords != 0 && (keywords&provider.keywordAny == 0 || keywords&provider.keywordAll != provider.keywordAll) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteEvent writes a single ETW event from the provider. The event is
|
||||||
|
// constructed based on the EventOpt and FieldOpt values that are passed as
|
||||||
|
// opts.
|
||||||
|
func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
|
||||||
|
options := eventOptions{descriptor: NewEventDescriptor()}
|
||||||
|
em := &EventMetadata{}
|
||||||
|
ed := &EventData{}
|
||||||
|
|
||||||
|
// We need to evaluate the EventOpts first since they might change tags, and
|
||||||
|
// we write out the tags before evaluating FieldOpts.
|
||||||
|
for _, opt := range eventOpts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
em.WriteEventHeader(name, options.tags)
|
||||||
|
|
||||||
|
for _, opt := range fieldOpts {
|
||||||
|
opt(em, ed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't pass a data blob if there is no event data. There will always be
|
||||||
|
// event metadata (e.g. for the name) so we don't need to do this check for
|
||||||
|
// the metadata.
|
||||||
|
dataBlobs := [][]byte{}
|
||||||
|
if len(ed.Bytes()) > 0 {
|
||||||
|
dataBlobs = [][]byte{ed.Bytes()}
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, dataBlobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteEventRaw writes a single ETW event from the provider. This function is
|
||||||
|
// less abstracted than WriteEvent, and presents a fairly direct interface to
|
||||||
|
// the event writing functionality. It expects a series of event metadata and
|
||||||
|
// event data blobs to be passed in, which must conform to the TraceLogging
|
||||||
|
// schema. The functions on EventMetadata and EventData can help with creating
|
||||||
|
// these blobs. The blobs of each type are effectively concatenated together by
|
||||||
|
// the ETW infrastructure.
|
||||||
|
func (provider *Provider) WriteEventRaw(
|
||||||
|
descriptor *EventDescriptor,
|
||||||
|
activityID *windows.GUID,
|
||||||
|
relatedActivityID *windows.GUID,
|
||||||
|
metadataBlobs [][]byte,
|
||||||
|
dataBlobs [][]byte) error {
|
||||||
|
|
||||||
|
dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
|
||||||
|
dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
|
||||||
|
|
||||||
|
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
|
||||||
|
for _, blob := range metadataBlobs {
|
||||||
|
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
|
||||||
|
}
|
||||||
|
for _, blob := range dataBlobs {
|
||||||
|
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0])
|
||||||
|
}
|
52
vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go
generated
vendored
Normal file
52
vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Because the provider callback function needs to be able to access the
|
||||||
|
// provider data when it is invoked by ETW, we need to keep provider data stored
|
||||||
|
// in a global map based on an index. The index is passed as the callback
|
||||||
|
// context to ETW.
|
||||||
|
type providerMap struct {
|
||||||
|
m map[uint]*Provider
|
||||||
|
i uint
|
||||||
|
lock sync.Mutex
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
var providers = providerMap{
|
||||||
|
m: make(map[uint]*Provider),
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *providerMap) newProvider() *Provider {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
i := p.i
|
||||||
|
p.i++
|
||||||
|
|
||||||
|
provider := &Provider{
|
||||||
|
index: i,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.m[i] = provider
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *providerMap) removeProvider(provider *Provider) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
delete(p.m, provider.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *providerMap) getProvider(index uint) *Provider {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
return p.m[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerCallbackOnce sync.Once
|
||||||
|
var globalProviderCallback uintptr
|
16
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go
generated
vendored
Normal file
16
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// +build 386 arm
|
||||||
|
|
||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
|
||||||
|
// be 64 bits, regardless of the actual size of a pointer on the platform. This
|
||||||
|
// is intended for use with certain Windows APIs that expect a pointer as a
|
||||||
|
// ULONGLONG.
|
||||||
|
type ptr64 struct {
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
_ uint32
|
||||||
|
}
|
15
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go
generated
vendored
Normal file
15
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// +build amd64 arm64
|
||||||
|
|
||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
|
||||||
|
// be 64 bits, regardless of the actual size of a pointer on the platform. This
|
||||||
|
// is intended for use with certain Windows APIs that expect a pointer as a
|
||||||
|
// ULONGLONG.
|
||||||
|
type ptr64 struct {
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
78
vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go
generated
vendored
Normal file
78
vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Code generated by 'go generate'; DO NOT EDIT.
|
||||||
|
|
||||||
|
package etw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||||
|
|
||||||
|
procEventRegister = modadvapi32.NewProc("EventRegister")
|
||||||
|
procEventUnregister = modadvapi32.NewProc("EventUnregister")
|
||||||
|
procEventWriteTransfer = modadvapi32.NewProc("EventWriteTransfer")
|
||||||
|
procEventSetInformation = modadvapi32.NewProc("EventSetInformation")
|
||||||
|
)
|
||||||
|
|
||||||
|
func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procEventRegister.Addr(), 4, uintptr(unsafe.Pointer(providerId)), uintptr(callback), uintptr(callbackContext), uintptr(unsafe.Pointer(providerHandle)), 0, 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
win32err = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func eventUnregister(providerHandle providerHandle) (win32err error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
win32err = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
|
||||||
|
if r0 != 0 {
|
||||||
|
win32err = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
win32err = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
192
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
Normal file
192
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package etwlogrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/internal/etw"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hook is a Logrus hook which logs received events to ETW.
|
||||||
|
type Hook struct {
|
||||||
|
provider *etw.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHook registers a new ETW provider and returns a hook to log from it.
|
||||||
|
func NewHook(providerName string) (*Hook, error) {
|
||||||
|
hook := Hook{}
|
||||||
|
|
||||||
|
provider, err := etw.NewProvider(providerName, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hook.provider = provider
|
||||||
|
|
||||||
|
return &hook, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels returns the set of levels that this hook wants to receive log entries
|
||||||
|
// for.
|
||||||
|
func (h *Hook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.TraceLevel,
|
||||||
|
logrus.DebugLevel,
|
||||||
|
logrus.InfoLevel,
|
||||||
|
logrus.WarnLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire receives each Logrus entry as it is logged, and logs it to ETW.
|
||||||
|
func (h *Hook) Fire(e *logrus.Entry) error {
|
||||||
|
level := etw.Level(e.Level)
|
||||||
|
if !h.provider.IsEnabledForLevel(level) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve extra space for the message field.
|
||||||
|
fields := make([]etw.FieldOpt, 0, len(e.Data)+1)
|
||||||
|
|
||||||
|
fields = append(fields, etw.StringField("Message", e.Message))
|
||||||
|
|
||||||
|
for k, v := range e.Data {
|
||||||
|
fields = append(fields, getFieldOpt(k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could try to map Logrus levels to ETW levels, but we would lose some
|
||||||
|
// fidelity as there are fewer ETW levels. So instead we use the level
|
||||||
|
// directly.
|
||||||
|
return h.provider.WriteEvent(
|
||||||
|
"LogrusEntry",
|
||||||
|
etw.WithEventOpts(etw.WithLevel(level)),
|
||||||
|
fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently, we support logging basic builtin types (int, string, etc), slices
|
||||||
|
// of basic builtin types, error, types derived from the basic types (e.g. "type
|
||||||
|
// foo int"), and structs (recursively logging their fields). We do not support
|
||||||
|
// slices of derived types (e.g. "[]foo").
|
||||||
|
//
|
||||||
|
// For types that we don't support, the value is formatted via fmt.Sprint, and
|
||||||
|
// we also log a message that the type is unsupported along with the formatted
|
||||||
|
// type. The intent of this is to make it easier to see which types are not
|
||||||
|
// supported in traces, so we can evaluate adding support for more types in the
|
||||||
|
// future.
|
||||||
|
func getFieldOpt(k string, v interface{}) etw.FieldOpt {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case bool:
|
||||||
|
return etw.BoolField(k, v)
|
||||||
|
case []bool:
|
||||||
|
return etw.BoolArray(k, v)
|
||||||
|
case string:
|
||||||
|
return etw.StringField(k, v)
|
||||||
|
case []string:
|
||||||
|
return etw.StringArray(k, v)
|
||||||
|
case int:
|
||||||
|
return etw.IntField(k, v)
|
||||||
|
case []int:
|
||||||
|
return etw.IntArray(k, v)
|
||||||
|
case int8:
|
||||||
|
return etw.Int8Field(k, v)
|
||||||
|
case []int8:
|
||||||
|
return etw.Int8Array(k, v)
|
||||||
|
case int16:
|
||||||
|
return etw.Int16Field(k, v)
|
||||||
|
case []int16:
|
||||||
|
return etw.Int16Array(k, v)
|
||||||
|
case int32:
|
||||||
|
return etw.Int32Field(k, v)
|
||||||
|
case []int32:
|
||||||
|
return etw.Int32Array(k, v)
|
||||||
|
case int64:
|
||||||
|
return etw.Int64Field(k, v)
|
||||||
|
case []int64:
|
||||||
|
return etw.Int64Array(k, v)
|
||||||
|
case uint:
|
||||||
|
return etw.UintField(k, v)
|
||||||
|
case []uint:
|
||||||
|
return etw.UintArray(k, v)
|
||||||
|
case uint8:
|
||||||
|
return etw.Uint8Field(k, v)
|
||||||
|
case []uint8:
|
||||||
|
return etw.Uint8Array(k, v)
|
||||||
|
case uint16:
|
||||||
|
return etw.Uint16Field(k, v)
|
||||||
|
case []uint16:
|
||||||
|
return etw.Uint16Array(k, v)
|
||||||
|
case uint32:
|
||||||
|
return etw.Uint32Field(k, v)
|
||||||
|
case []uint32:
|
||||||
|
return etw.Uint32Array(k, v)
|
||||||
|
case uint64:
|
||||||
|
return etw.Uint64Field(k, v)
|
||||||
|
case []uint64:
|
||||||
|
return etw.Uint64Array(k, v)
|
||||||
|
case uintptr:
|
||||||
|
return etw.UintptrField(k, v)
|
||||||
|
case []uintptr:
|
||||||
|
return etw.UintptrArray(k, v)
|
||||||
|
case float32:
|
||||||
|
return etw.Float32Field(k, v)
|
||||||
|
case []float32:
|
||||||
|
return etw.Float32Array(k, v)
|
||||||
|
case float64:
|
||||||
|
return etw.Float64Field(k, v)
|
||||||
|
case []float64:
|
||||||
|
return etw.Float64Array(k, v)
|
||||||
|
case error:
|
||||||
|
return etw.StringField(k, v.Error())
|
||||||
|
default:
|
||||||
|
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return getFieldOpt(k, rv.Bool())
|
||||||
|
case reflect.Int:
|
||||||
|
return getFieldOpt(k, int(rv.Int()))
|
||||||
|
case reflect.Int8:
|
||||||
|
return getFieldOpt(k, int8(rv.Int()))
|
||||||
|
case reflect.Int16:
|
||||||
|
return getFieldOpt(k, int16(rv.Int()))
|
||||||
|
case reflect.Int32:
|
||||||
|
return getFieldOpt(k, int32(rv.Int()))
|
||||||
|
case reflect.Int64:
|
||||||
|
return getFieldOpt(k, int64(rv.Int()))
|
||||||
|
case reflect.Uint:
|
||||||
|
return getFieldOpt(k, uint(rv.Uint()))
|
||||||
|
case reflect.Uint8:
|
||||||
|
return getFieldOpt(k, uint8(rv.Uint()))
|
||||||
|
case reflect.Uint16:
|
||||||
|
return getFieldOpt(k, uint16(rv.Uint()))
|
||||||
|
case reflect.Uint32:
|
||||||
|
return getFieldOpt(k, uint32(rv.Uint()))
|
||||||
|
case reflect.Uint64:
|
||||||
|
return getFieldOpt(k, uint64(rv.Uint()))
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return getFieldOpt(k, uintptr(rv.Uint()))
|
||||||
|
case reflect.Float32:
|
||||||
|
return getFieldOpt(k, float32(rv.Float()))
|
||||||
|
case reflect.Float64:
|
||||||
|
return getFieldOpt(k, float64(rv.Float()))
|
||||||
|
case reflect.String:
|
||||||
|
return getFieldOpt(k, rv.String())
|
||||||
|
case reflect.Struct:
|
||||||
|
fields := make([]etw.FieldOpt, 0, rv.NumField())
|
||||||
|
for i := 0; i < rv.NumField(); i++ {
|
||||||
|
field := rv.Field(i)
|
||||||
|
if field.CanInterface() {
|
||||||
|
fields = append(fields, getFieldOpt(k, field.Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return etw.Struct(k, fields...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up the hook and closes the ETW provider.
|
||||||
|
func (h *Hook) Close() error {
|
||||||
|
return h.provider.Close()
|
||||||
|
}
|
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
Normal file
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Windows Terminal Sequences
|
||||||
|
|
||||||
|
This library allow for enabling Windows terminal color support for Go.
|
||||||
|
|
||||||
|
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
||||||
|
|
||||||
|
We thank all the authors who provided code to this library:
|
||||||
|
|
||||||
|
* Felix Kollmann
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package sequences
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
|
||||||
|
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
||||||
|
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
|
||||||
|
|
||||||
|
var mode uint32
|
||||||
|
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if enable {
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
} else {
|
||||||
|
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
|
||||||
|
if ret == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
95
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
95
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
@ -56,8 +56,39 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased
|
|||||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
exit status 1
|
|
||||||
```
|
```
|
||||||
|
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.SetFormatter(&log.TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
FullTimestamp: true,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logging Method Name
|
||||||
|
|
||||||
|
If you wish to add the calling method as a field, instruct the logger via:
|
||||||
|
```go
|
||||||
|
log.SetReportCaller(true)
|
||||||
|
```
|
||||||
|
This adds the caller as 'method' like so:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
||||||
|
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
||||||
|
```
|
||||||
|
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
||||||
|
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
||||||
|
environment via benchmarks:
|
||||||
|
```
|
||||||
|
go test -bench=.*CallerTracing
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Case-sensitivity
|
#### Case-sensitivity
|
||||||
|
|
||||||
@ -220,7 +251,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
|||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
||||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
)
|
)
|
||||||
@ -241,60 +272,15 @@ func init() {
|
|||||||
```
|
```
|
||||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||||
|
|
||||||
| Hook | Description |
|
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
||||||
| ----- | ----------- |
|
|
||||||
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
|
||||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
|
||||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
|
||||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
|
||||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
|
||||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
|
||||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
|
||||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
|
||||||
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
|
|
||||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
|
||||||
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
|
|
||||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
|
||||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
|
||||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
|
||||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
|
||||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
|
||||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
|
||||||
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
|
||||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
|
||||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
|
||||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
|
||||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
|
||||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
|
||||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
|
||||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
|
||||||
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
|
||||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
|
||||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
|
||||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
|
||||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
|
||||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
|
||||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
|
||||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
|
||||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
|
||||||
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
|
||||||
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
|
|
||||||
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
|
||||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
|
||||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
|
||||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
|
||||||
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
|
||||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
|
||||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
|
||||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
|
||||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
|
||||||
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
|
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
log.Trace("Something very low level.")
|
||||||
log.Debug("Useful debugging information.")
|
log.Debug("Useful debugging information.")
|
||||||
log.Info("Something noteworthy happened!")
|
log.Info("Something noteworthy happened!")
|
||||||
log.Warn("You should probably take a look at this.")
|
log.Warn("You should probably take a look at this.")
|
||||||
@ -366,13 +352,16 @@ The built-in logging formatters are:
|
|||||||
field to `true`. To force no colored output even if there is a TTY set the
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
`DisableColors` field to `true`. For Windows, see
|
`DisableColors` field to `true`. For Windows, see
|
||||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||||
|
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||||
|
truncation set the `DisableLevelTruncation` field to `true`.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can by parsed by Kubernetes and Google Container Engine.
|
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
||||||
|
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
|
||||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
@ -489,7 +478,7 @@ logrus.RegisterExitHandler(handler)
|
|||||||
|
|
||||||
#### Thread safety
|
#### Thread safety
|
||||||
|
|
||||||
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
|
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
|
||||||
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
||||||
|
|
||||||
Situation when locking is not needed includes:
|
Situation when locking is not needed includes:
|
||||||
|
287
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
287
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
@ -4,11 +4,30 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bufferPool *sync.Pool
|
var (
|
||||||
|
bufferPool *sync.Pool
|
||||||
|
|
||||||
|
// qualified package name, cached at first use
|
||||||
|
logrusPackage string
|
||||||
|
|
||||||
|
// Positions in the call stack when tracing to report the calling method
|
||||||
|
minimumCallerDepth int
|
||||||
|
|
||||||
|
// Used for caller information initialisation
|
||||||
|
callerInitOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maximumCallerDepth int = 25
|
||||||
|
knownLogrusFrames int = 4
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
bufferPool = &sync.Pool{
|
bufferPool = &sync.Pool{
|
||||||
@ -16,15 +35,18 @@ func init() {
|
|||||||
return new(bytes.Buffer)
|
return new(bytes.Buffer)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start at the bottom of the stack before the package-name cache is primed
|
||||||
|
minimumCallerDepth = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines the key when adding errors using WithError.
|
// Defines the key when adding errors using WithError.
|
||||||
var ErrorKey = "error"
|
var ErrorKey = "error"
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
||||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
||||||
// passed around as much as you wish to avoid field duplication.
|
// reused and passed around as much as you wish to avoid field duplication.
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Logger *Logger
|
Logger *Logger
|
||||||
|
|
||||||
@ -34,22 +56,28 @@ type Entry struct {
|
|||||||
// Time at which the log entry was created
|
// Time at which the log entry was created
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
|
||||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||||
Level Level
|
Level Level
|
||||||
|
|
||||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
// Calling method, with package name
|
||||||
|
Caller *runtime.Frame
|
||||||
|
|
||||||
|
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
// When formatter is called in entry.log(), an Buffer may be set to entry
|
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||||
Buffer *bytes.Buffer
|
Buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// err may contain a field formatting error
|
||||||
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEntry(logger *Logger) *Entry {
|
func NewEntry(logger *Logger) *Entry {
|
||||||
return &Entry{
|
return &Entry{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
// Default is three fields, give a little extra room
|
// Default is three fields, plus one optional. Give a little extra room.
|
||||||
Data: make(Fields, 5),
|
Data: make(Fields, 6),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,43 +108,117 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
|
fieldErr := entry.err
|
||||||
for k, v := range fields {
|
for k, v := range fields {
|
||||||
|
isErrField := false
|
||||||
|
if t := reflect.TypeOf(v); t != nil {
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Func:
|
||||||
|
isErrField = true
|
||||||
|
case reflect.Ptr:
|
||||||
|
isErrField = t.Elem().Kind() == reflect.Func
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isErrField {
|
||||||
|
tmp := fmt.Sprintf("can not add field %q", k)
|
||||||
|
if fieldErr != "" {
|
||||||
|
fieldErr = entry.err + ", " + tmp
|
||||||
|
} else {
|
||||||
|
fieldErr = tmp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
return &Entry{Logger: entry.Logger, Data: data}
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides the time of the Entry.
|
||||||
|
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||||
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPackageName reduces a fully qualified function name to the package name
|
||||||
|
// There really ought to be to be a better way...
|
||||||
|
func getPackageName(f string) string {
|
||||||
|
for {
|
||||||
|
lastPeriod := strings.LastIndex(f, ".")
|
||||||
|
lastSlash := strings.LastIndex(f, "/")
|
||||||
|
if lastPeriod > lastSlash {
|
||||||
|
f = f[:lastPeriod]
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCaller retrieves the name of the first non-logrus calling function
|
||||||
|
func getCaller() *runtime.Frame {
|
||||||
|
// Restrict the lookback frames to avoid runaway lookups
|
||||||
|
pcs := make([]uintptr, maximumCallerDepth)
|
||||||
|
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||||
|
frames := runtime.CallersFrames(pcs[:depth])
|
||||||
|
|
||||||
|
// cache this package's fully-qualified name
|
||||||
|
callerInitOnce.Do(func() {
|
||||||
|
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
||||||
|
|
||||||
|
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||||
|
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
||||||
|
minimumCallerDepth = knownLogrusFrames
|
||||||
|
})
|
||||||
|
|
||||||
|
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||||
|
pkg := getPackageName(f.Function)
|
||||||
|
|
||||||
|
// If the caller isn't part of this package, we're done
|
||||||
|
if pkg != logrusPackage {
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we got here, we failed to find the caller's context
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry Entry) HasCaller() (has bool) {
|
||||||
|
return entry.Logger != nil &&
|
||||||
|
entry.Logger.ReportCaller &&
|
||||||
|
entry.Caller != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is not declared with a pointer value because otherwise
|
// This function is not declared with a pointer value because otherwise
|
||||||
// race conditions will occur when using multiple goroutines
|
// race conditions will occur when using multiple goroutines
|
||||||
func (entry Entry) log(level Level, msg string) {
|
func (entry Entry) log(level Level, msg string) {
|
||||||
var buffer *bytes.Buffer
|
var buffer *bytes.Buffer
|
||||||
|
|
||||||
|
// Default to now, but allow users to override if they want.
|
||||||
|
//
|
||||||
|
// We don't have to worry about polluting future calls to Entry#log()
|
||||||
|
// with this assignment because this function is declared with a
|
||||||
|
// non-pointer receiver.
|
||||||
|
if entry.Time.IsZero() {
|
||||||
entry.Time = time.Now()
|
entry.Time = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
entry.Level = level
|
entry.Level = level
|
||||||
entry.Message = msg
|
entry.Message = msg
|
||||||
|
if entry.Logger.ReportCaller {
|
||||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
entry.Caller = getCaller()
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry.fireHooks()
|
||||||
|
|
||||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||||
buffer.Reset()
|
buffer.Reset()
|
||||||
defer bufferPool.Put(buffer)
|
defer bufferPool.Put(buffer)
|
||||||
entry.Buffer = buffer
|
entry.Buffer = buffer
|
||||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
|
||||||
|
entry.write()
|
||||||
|
|
||||||
entry.Buffer = nil
|
entry.Buffer = nil
|
||||||
if err != nil {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
} else {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
_, err = entry.Logger.Out.Write(serialized)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
|
||||||
}
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid Entry#log() returning a value that only would make sense for
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
@ -126,26 +228,53 @@ func (entry Entry) log(level Level, msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
func (entry *Entry) fireHooks() {
|
||||||
if entry.Logger.level() >= DebugLevel {
|
entry.Logger.mu.Lock()
|
||||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
defer entry.Logger.mu.Unlock()
|
||||||
|
err := entry.Logger.Hooks.Fire(entry.Level, entry)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) write() {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
} else {
|
||||||
|
_, err = entry.Logger.Out.Write(serialized)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Log(level Level, args ...interface{}) {
|
||||||
|
if entry.Logger.IsLevelEnabled(level) {
|
||||||
|
entry.log(level, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Trace(args ...interface{}) {
|
||||||
|
entry.Log(TraceLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
entry.Log(DebugLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Print(args ...interface{}) {
|
func (entry *Entry) Print(args ...interface{}) {
|
||||||
entry.Info(args...)
|
entry.Info(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Info(args ...interface{}) {
|
func (entry *Entry) Info(args ...interface{}) {
|
||||||
if entry.Logger.level() >= InfoLevel {
|
entry.Log(InfoLevel, args...)
|
||||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warn(args ...interface{}) {
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
if entry.Logger.level() >= WarnLevel {
|
entry.Log(WarnLevel, args...)
|
||||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warning(args ...interface{}) {
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
@ -153,37 +282,35 @@ func (entry *Entry) Warning(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Error(args ...interface{}) {
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
if entry.Logger.level() >= ErrorLevel {
|
entry.Log(ErrorLevel, args...)
|
||||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Fatal(args ...interface{}) {
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
if entry.Logger.level() >= FatalLevel {
|
entry.Log(FatalLevel, args...)
|
||||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
entry.Logger.Exit(1)
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panic(args ...interface{}) {
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
if entry.Logger.level() >= PanicLevel {
|
entry.Log(PanicLevel, args...)
|
||||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
panic(fmt.Sprint(args...))
|
panic(fmt.Sprint(args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry Printf family functions
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||||
|
entry.Log(level, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||||
|
entry.Logf(TraceLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= DebugLevel {
|
entry.Logf(DebugLevel, format, args...)
|
||||||
entry.Debug(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= InfoLevel {
|
entry.Logf(InfoLevel, format, args...)
|
||||||
entry.Info(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
@ -191,9 +318,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= WarnLevel {
|
entry.Logf(WarnLevel, format, args...)
|
||||||
entry.Warn(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
@ -201,36 +326,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= ErrorLevel {
|
entry.Logf(ErrorLevel, format, args...)
|
||||||
entry.Error(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= FatalLevel {
|
entry.Logf(FatalLevel, format, args...)
|
||||||
entry.Fatal(fmt.Sprintf(format, args...))
|
entry.Logger.Exit(1)
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
if entry.Logger.level() >= PanicLevel {
|
entry.Logf(PanicLevel, format, args...)
|
||||||
entry.Panic(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry Println family functions
|
// Entry Println family functions
|
||||||
|
|
||||||
func (entry *Entry) Debugln(args ...interface{}) {
|
func (entry *Entry) Logln(level Level, args ...interface{}) {
|
||||||
if entry.Logger.level() >= DebugLevel {
|
if entry.Logger.IsLevelEnabled(level) {
|
||||||
entry.Debug(entry.sprintlnn(args...))
|
entry.Log(level, entry.sprintlnn(args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Traceln(args ...interface{}) {
|
||||||
|
entry.Logln(TraceLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
|
entry.Logln(DebugLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (entry *Entry) Infoln(args ...interface{}) {
|
func (entry *Entry) Infoln(args ...interface{}) {
|
||||||
if entry.Logger.level() >= InfoLevel {
|
entry.Logln(InfoLevel, args...)
|
||||||
entry.Info(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Println(args ...interface{}) {
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
@ -238,9 +363,7 @@ func (entry *Entry) Println(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warnln(args ...interface{}) {
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
if entry.Logger.level() >= WarnLevel {
|
entry.Logln(WarnLevel, args...)
|
||||||
entry.Warn(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Warningln(args ...interface{}) {
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
@ -248,22 +371,16 @@ func (entry *Entry) Warningln(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Errorln(args ...interface{}) {
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
if entry.Logger.level() >= ErrorLevel {
|
entry.Logln(ErrorLevel, args...)
|
||||||
entry.Error(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
if entry.Logger.level() >= FatalLevel {
|
entry.Logln(FatalLevel, args...)
|
||||||
entry.Fatal(entry.sprintlnn(args...))
|
entry.Logger.Exit(1)
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
if entry.Logger.level() >= PanicLevel {
|
entry.Logln(PanicLevel, args...)
|
||||||
entry.Panic(entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
60
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
60
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
@ -2,6 +2,7 @@ package logrus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -15,37 +16,38 @@ func StandardLogger() *Logger {
|
|||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
// SetOutput sets the standard logger output.
|
||||||
func SetOutput(out io.Writer) {
|
func SetOutput(out io.Writer) {
|
||||||
std.mu.Lock()
|
std.SetOutput(out)
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Out = out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFormatter sets the standard logger formatter.
|
// SetFormatter sets the standard logger formatter.
|
||||||
func SetFormatter(formatter Formatter) {
|
func SetFormatter(formatter Formatter) {
|
||||||
std.mu.Lock()
|
std.SetFormatter(formatter)
|
||||||
defer std.mu.Unlock()
|
}
|
||||||
std.Formatter = formatter
|
|
||||||
|
// SetReportCaller sets whether the standard logger will include the calling
|
||||||
|
// method as a field.
|
||||||
|
func SetReportCaller(include bool) {
|
||||||
|
std.SetReportCaller(include)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLevel sets the standard logger level.
|
// SetLevel sets the standard logger level.
|
||||||
func SetLevel(level Level) {
|
func SetLevel(level Level) {
|
||||||
std.mu.Lock()
|
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.SetLevel(level)
|
std.SetLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLevel returns the standard logger level.
|
// GetLevel returns the standard logger level.
|
||||||
func GetLevel() Level {
|
func GetLevel() Level {
|
||||||
std.mu.Lock()
|
return std.GetLevel()
|
||||||
defer std.mu.Unlock()
|
}
|
||||||
return std.level()
|
|
||||||
|
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
||||||
|
func IsLevelEnabled(level Level) bool {
|
||||||
|
return std.IsLevelEnabled(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHook adds a hook to the standard logger hooks.
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
func AddHook(hook Hook) {
|
func AddHook(hook Hook) {
|
||||||
std.mu.Lock()
|
std.AddHook(hook)
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.Hooks.Add(hook)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
@ -72,6 +74,20 @@ func WithFields(fields Fields) *Entry {
|
|||||||
return std.WithFields(fields)
|
return std.WithFields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTime creats an entry from the standard logger and overrides the time of
|
||||||
|
// logs generated with it.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithTime(t time.Time) *Entry {
|
||||||
|
return std.WithTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace logs a message at level Trace on the standard logger.
|
||||||
|
func Trace(args ...interface{}) {
|
||||||
|
std.Trace(args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
func Debug(args ...interface{}) {
|
func Debug(args ...interface{}) {
|
||||||
std.Debug(args...)
|
std.Debug(args...)
|
||||||
@ -107,11 +123,16 @@ func Panic(args ...interface{}) {
|
|||||||
std.Panic(args...)
|
std.Panic(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal logs a message at level Fatal on the standard logger.
|
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatal(args ...interface{}) {
|
func Fatal(args ...interface{}) {
|
||||||
std.Fatal(args...)
|
std.Fatal(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tracef logs a message at level Trace on the standard logger.
|
||||||
|
func Tracef(format string, args ...interface{}) {
|
||||||
|
std.Tracef(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugf logs a message at level Debug on the standard logger.
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
func Debugf(format string, args ...interface{}) {
|
func Debugf(format string, args ...interface{}) {
|
||||||
std.Debugf(format, args...)
|
std.Debugf(format, args...)
|
||||||
@ -147,11 +168,16 @@ func Panicf(format string, args ...interface{}) {
|
|||||||
std.Panicf(format, args...)
|
std.Panicf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf logs a message at level Fatal on the standard logger.
|
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...interface{}) {
|
||||||
std.Fatalf(format, args...)
|
std.Fatalf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Traceln logs a message at level Trace on the standard logger.
|
||||||
|
func Traceln(args ...interface{}) {
|
||||||
|
std.Traceln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugln logs a message at level Debug on the standard logger.
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
func Debugln(args ...interface{}) {
|
func Debugln(args ...interface{}) {
|
||||||
std.Debugln(args...)
|
std.Debugln(args...)
|
||||||
@ -187,7 +213,7 @@ func Panicln(args ...interface{}) {
|
|||||||
std.Panicln(args...)
|
std.Panicln(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalln logs a message at level Fatal on the standard logger.
|
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||||
func Fatalln(args ...interface{}) {
|
func Fatalln(args ...interface{}) {
|
||||||
std.Fatalln(args...)
|
std.Fatalln(args...)
|
||||||
}
|
}
|
||||||
|
51
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
51
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
@ -2,7 +2,16 @@ package logrus
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const defaultTimestampFormat = time.RFC3339
|
// Default key names for the default fields
|
||||||
|
const (
|
||||||
|
defaultTimestampFormat = time.RFC3339
|
||||||
|
FieldKeyMsg = "msg"
|
||||||
|
FieldKeyLevel = "level"
|
||||||
|
FieldKeyTime = "time"
|
||||||
|
FieldKeyLogrusError = "logrus_error"
|
||||||
|
FieldKeyFunc = "func"
|
||||||
|
FieldKeyFile = "file"
|
||||||
|
)
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
@ -18,7 +27,7 @@ type Formatter interface {
|
|||||||
Format(*Entry) ([]byte, error)
|
Format(*Entry) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
||||||
// dumping it. If this code wasn't there doing:
|
// dumping it. If this code wasn't there doing:
|
||||||
//
|
//
|
||||||
// logrus.WithField("level", 1).Info("hello")
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
@ -30,16 +39,40 @@ type Formatter interface {
|
|||||||
//
|
//
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
// avoid code duplication between the two default formatters.
|
// avoid code duplication between the two default formatters.
|
||||||
func prefixFieldClashes(data Fields) {
|
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
|
||||||
if t, ok := data["time"]; ok {
|
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||||
data["fields.time"] = t
|
if t, ok := data[timeKey]; ok {
|
||||||
|
data["fields."+timeKey] = t
|
||||||
|
delete(data, timeKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m, ok := data["msg"]; ok {
|
msgKey := fieldMap.resolve(FieldKeyMsg)
|
||||||
data["fields.msg"] = m
|
if m, ok := data[msgKey]; ok {
|
||||||
|
data["fields."+msgKey] = m
|
||||||
|
delete(data, msgKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l, ok := data["level"]; ok {
|
levelKey := fieldMap.resolve(FieldKeyLevel)
|
||||||
data["fields.level"] = l
|
if l, ok := data[levelKey]; ok {
|
||||||
|
data["fields."+levelKey] = l
|
||||||
|
delete(data, levelKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
||||||
|
if l, ok := data[logrusErrKey]; ok {
|
||||||
|
data["fields."+logrusErrKey] = l
|
||||||
|
delete(data, logrusErrKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If reportCaller is not set, 'func' will not conflict.
|
||||||
|
if reportCaller {
|
||||||
|
funcKey := fieldMap.resolve(FieldKeyFunc)
|
||||||
|
if l, ok := data[funcKey]; ok {
|
||||||
|
data["fields."+funcKey] = l
|
||||||
|
}
|
||||||
|
fileKey := fieldMap.resolve(FieldKeyFile)
|
||||||
|
if l, ok := data[fileKey]; ok {
|
||||||
|
data["fields."+fileKey] = l
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
50
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
@ -1,6 +1,7 @@
|
|||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
@ -10,13 +11,6 @@ type fieldKey string
|
|||||||
// FieldMap allows customization of the key names for default fields.
|
// FieldMap allows customization of the key names for default fields.
|
||||||
type FieldMap map[fieldKey]string
|
type FieldMap map[fieldKey]string
|
||||||
|
|
||||||
// Default key names for the default fields
|
|
||||||
const (
|
|
||||||
FieldKeyMsg = "msg"
|
|
||||||
FieldKeyLevel = "level"
|
|
||||||
FieldKeyTime = "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f FieldMap) resolve(key fieldKey) string {
|
func (f FieldMap) resolve(key fieldKey) string {
|
||||||
if k, ok := f[key]; ok {
|
if k, ok := f[key]; ok {
|
||||||
return k
|
return k
|
||||||
@ -33,6 +27,9 @@ type JSONFormatter struct {
|
|||||||
// DisableTimestamp allows disabling automatic timestamps in output
|
// DisableTimestamp allows disabling automatic timestamps in output
|
||||||
DisableTimestamp bool
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
||||||
|
DataKey string
|
||||||
|
|
||||||
// FieldMap allows users to customize the names of keys for default fields.
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||||
// As an example:
|
// As an example:
|
||||||
// formatter := &JSONFormatter{
|
// formatter := &JSONFormatter{
|
||||||
@ -40,14 +37,18 @@ type JSONFormatter struct {
|
|||||||
// FieldKeyTime: "@timestamp",
|
// FieldKeyTime: "@timestamp",
|
||||||
// FieldKeyLevel: "@level",
|
// FieldKeyLevel: "@level",
|
||||||
// FieldKeyMsg: "@message",
|
// FieldKeyMsg: "@message",
|
||||||
|
// FieldKeyFunc: "@caller",
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
FieldMap FieldMap
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
// PrettyPrint will indent all json logs
|
||||||
|
PrettyPrint bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format renders a single log entry
|
// Format renders a single log entry
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+4)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case error:
|
case error:
|
||||||
@ -58,22 +59,47 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefixFieldClashes(data)
|
|
||||||
|
if f.DataKey != "" {
|
||||||
|
newData := make(Fields, 4)
|
||||||
|
newData[f.DataKey] = data
|
||||||
|
data = newData
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
timestampFormat = defaultTimestampFormat
|
timestampFormat = defaultTimestampFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if entry.err != "" {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
||||||
|
}
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
||||||
}
|
}
|
||||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||||
|
if entry.HasCaller() {
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
||||||
|
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
}
|
||||||
|
|
||||||
serialized, err := json.Marshal(data)
|
var b *bytes.Buffer
|
||||||
if err != nil {
|
if entry.Buffer != nil {
|
||||||
|
b = entry.Buffer
|
||||||
|
} else {
|
||||||
|
b = &bytes.Buffer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(b)
|
||||||
|
if f.PrettyPrint {
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
}
|
||||||
|
if err := encoder.Encode(data); err != nil {
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
}
|
}
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
228
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
228
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
@ -5,12 +5,13 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
// something more adventorous, such as logging to Kafka.
|
// something more adventurous, such as logging to Kafka.
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
// Hooks for the logger instance. These allow firing events based on logging
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
// levels and log entries. For example, to send errors to an error tracking
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
@ -23,6 +24,10 @@ type Logger struct {
|
|||||||
// own that implements the `Formatter` interface, see the `README` or included
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
// formatters for examples.
|
// formatters for examples.
|
||||||
Formatter Formatter
|
Formatter Formatter
|
||||||
|
|
||||||
|
// Flag for whether to log caller info (off by default)
|
||||||
|
ReportCaller bool
|
||||||
|
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
// logged.
|
// logged.
|
||||||
@ -31,8 +36,12 @@ type Logger struct {
|
|||||||
mu MutexWrap
|
mu MutexWrap
|
||||||
// Reusable empty entry
|
// Reusable empty entry
|
||||||
entryPool sync.Pool
|
entryPool sync.Pool
|
||||||
|
// Function to exit the application, defaults to `os.Exit()`
|
||||||
|
ExitFunc exitFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type exitFunc func(int)
|
||||||
|
|
||||||
type MutexWrap struct {
|
type MutexWrap struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
disabled bool
|
disabled bool
|
||||||
@ -72,6 +81,8 @@ func New() *Logger {
|
|||||||
Formatter: new(TextFormatter),
|
Formatter: new(TextFormatter),
|
||||||
Hooks: make(LevelHooks),
|
Hooks: make(LevelHooks),
|
||||||
Level: InfoLevel,
|
Level: InfoLevel,
|
||||||
|
ExitFunc: os.Exit,
|
||||||
|
ReportCaller: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,11 +95,12 @@ func (logger *Logger) newEntry() *Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||||
|
entry.Data = map[string]interface{}{}
|
||||||
logger.entryPool.Put(entry)
|
logger.entryPool.Put(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a field to the log entry, note that it doesn't log until you call
|
// Adds a field to the log entry, note that it doesn't log until you call
|
||||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
|
||||||
// If you want multiple fields, use `WithFields`.
|
// If you want multiple fields, use `WithFields`.
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
@ -112,20 +124,31 @@ func (logger *Logger) WithError(err error) *Entry {
|
|||||||
return entry.WithError(err)
|
return entry.WithError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
// Overrides the time of the log entry.
|
||||||
if logger.level() >= DebugLevel {
|
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
entry.Debugf(format, args...)
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(level) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Logf(level, format, args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
||||||
|
logger.Logf(TraceLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
logger.Logf(DebugLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
if logger.level() >= InfoLevel {
|
logger.Logf(InfoLevel, format, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Infof(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
@ -135,60 +158,44 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Logf(WarnLevel, format, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Warnf(format, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
if logger.level() >= ErrorLevel {
|
logger.Logf(ErrorLevel, format, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Errorf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
if logger.level() >= FatalLevel {
|
logger.Logf(FatalLevel, format, args...)
|
||||||
entry := logger.newEntry()
|
logger.Exit(1)
|
||||||
entry.Fatalf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
if logger.level() >= PanicLevel {
|
logger.Logf(PanicLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Log(level Level, args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(level) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
entry.Panicf(format, args...)
|
entry.Log(level, args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Trace(args ...interface{}) {
|
||||||
|
logger.Log(TraceLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
if logger.level() >= DebugLevel {
|
logger.Log(DebugLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Debug(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
if logger.level() >= InfoLevel {
|
logger.Log(InfoLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Info(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
@ -198,60 +205,44 @@ func (logger *Logger) Print(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Log(WarnLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warn(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Warn(args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warn(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
if logger.level() >= ErrorLevel {
|
logger.Log(ErrorLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Error(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
if logger.level() >= FatalLevel {
|
logger.Log(FatalLevel, args...)
|
||||||
entry := logger.newEntry()
|
logger.Exit(1)
|
||||||
entry.Fatal(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
if logger.level() >= PanicLevel {
|
logger.Log(PanicLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
||||||
|
if logger.IsLevelEnabled(level) {
|
||||||
entry := logger.newEntry()
|
entry := logger.newEntry()
|
||||||
entry.Panic(args...)
|
entry.Logln(level, args...)
|
||||||
logger.releaseEntry(entry)
|
logger.releaseEntry(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Traceln(args ...interface{}) {
|
||||||
|
logger.Logln(TraceLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
if logger.level() >= DebugLevel {
|
logger.Logln(DebugLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Debugln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
if logger.level() >= InfoLevel {
|
logger.Logln(InfoLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Infoln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
@ -261,44 +252,32 @@ func (logger *Logger) Println(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Logln(WarnLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
if logger.level() >= WarnLevel {
|
logger.Warn(args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Warnln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
if logger.level() >= ErrorLevel {
|
logger.Logln(ErrorLevel, args...)
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Errorln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
if logger.level() >= FatalLevel {
|
logger.Logln(FatalLevel, args...)
|
||||||
entry := logger.newEntry()
|
logger.Exit(1)
|
||||||
entry.Fatalln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
if logger.level() >= PanicLevel {
|
logger.Logln(PanicLevel, args...)
|
||||||
entry := logger.newEntry()
|
}
|
||||||
entry.Panicln(args...)
|
|
||||||
logger.releaseEntry(entry)
|
func (logger *Logger) Exit(code int) {
|
||||||
|
runHandlers()
|
||||||
|
if logger.ExitFunc == nil {
|
||||||
|
logger.ExitFunc = os.Exit
|
||||||
}
|
}
|
||||||
|
logger.ExitFunc(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
//When file is opened with appending mode, it's safe to
|
//When file is opened with appending mode, it's safe to
|
||||||
@ -312,6 +291,53 @@ func (logger *Logger) level() Level {
|
|||||||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the logger level.
|
||||||
func (logger *Logger) SetLevel(level Level) {
|
func (logger *Logger) SetLevel(level Level) {
|
||||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLevel returns the logger level.
|
||||||
|
func (logger *Logger) GetLevel() Level {
|
||||||
|
return logger.level()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the logger hooks.
|
||||||
|
func (logger *Logger) AddHook(hook Hook) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
||||||
|
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
||||||
|
return logger.level() >= level
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the logger formatter.
|
||||||
|
func (logger *Logger) SetFormatter(formatter Formatter) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutput sets the logger output.
|
||||||
|
func (logger *Logger) SetOutput(output io.Writer) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.Out = output
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
||||||
|
logger.mu.Lock()
|
||||||
|
defer logger.mu.Unlock()
|
||||||
|
logger.ReportCaller = reportCaller
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||||
|
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||||
|
logger.mu.Lock()
|
||||||
|
oldHooks := logger.Hooks
|
||||||
|
logger.Hooks = hooks
|
||||||
|
logger.mu.Unlock()
|
||||||
|
return oldHooks
|
||||||
|
}
|
||||||
|
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
@ -14,22 +14,11 @@ type Level uint32
|
|||||||
|
|
||||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
func (level Level) String() string {
|
func (level Level) String() string {
|
||||||
switch level {
|
if b, err := level.MarshalText(); err == nil {
|
||||||
case DebugLevel:
|
return string(b)
|
||||||
return "debug"
|
} else {
|
||||||
case InfoLevel:
|
|
||||||
return "info"
|
|
||||||
case WarnLevel:
|
|
||||||
return "warning"
|
|
||||||
case ErrorLevel:
|
|
||||||
return "error"
|
|
||||||
case FatalLevel:
|
|
||||||
return "fatal"
|
|
||||||
case PanicLevel:
|
|
||||||
return "panic"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
@ -47,12 +36,47 @@ func ParseLevel(lvl string) (Level, error) {
|
|||||||
return InfoLevel, nil
|
return InfoLevel, nil
|
||||||
case "debug":
|
case "debug":
|
||||||
return DebugLevel, nil
|
return DebugLevel, nil
|
||||||
|
case "trace":
|
||||||
|
return TraceLevel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var l Level
|
var l Level
|
||||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (level *Level) UnmarshalText(text []byte) error {
|
||||||
|
l, err := ParseLevel(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*level = Level(l)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (level Level) MarshalText() ([]byte, error) {
|
||||||
|
switch level {
|
||||||
|
case TraceLevel:
|
||||||
|
return []byte("trace"), nil
|
||||||
|
case DebugLevel:
|
||||||
|
return []byte("debug"), nil
|
||||||
|
case InfoLevel:
|
||||||
|
return []byte("info"), nil
|
||||||
|
case WarnLevel:
|
||||||
|
return []byte("warning"), nil
|
||||||
|
case ErrorLevel:
|
||||||
|
return []byte("error"), nil
|
||||||
|
case FatalLevel:
|
||||||
|
return []byte("fatal"), nil
|
||||||
|
case PanicLevel:
|
||||||
|
return []byte("panic"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("not a valid lorus level %q", level)
|
||||||
|
}
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
// A constant exposing all logging levels
|
||||||
var AllLevels = []Level{
|
var AllLevels = []Level{
|
||||||
PanicLevel,
|
PanicLevel,
|
||||||
@ -61,6 +85,7 @@ var AllLevels = []Level{
|
|||||||
WarnLevel,
|
WarnLevel,
|
||||||
InfoLevel,
|
InfoLevel,
|
||||||
DebugLevel,
|
DebugLevel,
|
||||||
|
TraceLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
// These are the different logging levels. You can set the logging level to log
|
||||||
@ -69,7 +94,7 @@ const (
|
|||||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
// message passed to Debug, Info, ...
|
// message passed to Debug, Info, ...
|
||||||
PanicLevel Level = iota
|
PanicLevel Level = iota
|
||||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
|
||||||
// logging level is set to Panic.
|
// logging level is set to Panic.
|
||||||
FatalLevel
|
FatalLevel
|
||||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
@ -82,6 +107,8 @@ const (
|
|||||||
InfoLevel
|
InfoLevel
|
||||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
DebugLevel
|
DebugLevel
|
||||||
|
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
||||||
|
TraceLevel
|
||||||
)
|
)
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
@ -140,4 +167,20 @@ type FieldLogger interface {
|
|||||||
Errorln(args ...interface{})
|
Errorln(args ...interface{})
|
||||||
Fatalln(args ...interface{})
|
Fatalln(args ...interface{})
|
||||||
Panicln(args ...interface{})
|
Panicln(args ...interface{})
|
||||||
|
|
||||||
|
// IsDebugEnabled() bool
|
||||||
|
// IsInfoEnabled() bool
|
||||||
|
// IsWarnEnabled() bool
|
||||||
|
// IsErrorEnabled() bool
|
||||||
|
// IsFatalEnabled() bool
|
||||||
|
// IsPanicEnabled() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
|
||||||
|
// here for consistancy. Do not use. Use Logger or Entry instead.
|
||||||
|
type Ext1FieldLogger interface {
|
||||||
|
FieldLogger
|
||||||
|
Tracef(format string, args ...interface{})
|
||||||
|
Trace(args ...interface{})
|
||||||
|
Traceln(args ...interface{})
|
||||||
}
|
}
|
||||||
|
10
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
10
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
// +build darwin freebsd openbsd netbsd dragonfly
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TIOCGETA
|
|
||||||
|
|
||||||
type Termios unix.Termios
|
|
9
vendor/github.com/sirupsen/logrus/terminal_check_aix.go
generated
vendored
Normal file
9
vendor/github.com/sirupsen/logrus/terminal_check_aix.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// +build !appengine,!js,!windows,aix
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
return false
|
||||||
|
}
|
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
Normal file
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
return true
|
||||||
|
}
|
11
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
Normal file
11
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build js
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
return false
|
||||||
|
}
|
19
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
Normal file
19
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// +build !appengine,!js,!windows,!aix
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
return terminal.IsTerminal(int(v.Fd()))
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
20
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
Normal file
20
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// +build !appengine,!js,windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkIfTerminal(w io.Writer) bool {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
var mode uint32
|
||||||
|
err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode)
|
||||||
|
return err == nil
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
14
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
14
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
// Based on ssh/terminal:
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TCGETS
|
|
||||||
|
|
||||||
type Termios unix.Termios
|
|
8
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
8
vendor/github.com/sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func initTerminal(w io.Writer) {
|
||||||
|
}
|
18
vendor/github.com/sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
18
vendor/github.com/sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// +build !appengine,!js,windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initTerminal(w io.Writer) {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *os.File:
|
||||||
|
sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true)
|
||||||
|
}
|
||||||
|
}
|
158
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
158
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
@ -3,14 +3,12 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -24,6 +22,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
|
emptyFieldMap FieldMap
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -38,6 +37,9 @@ type TextFormatter struct {
|
|||||||
// Force disabling colors.
|
// Force disabling colors.
|
||||||
DisableColors bool
|
DisableColors bool
|
||||||
|
|
||||||
|
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
|
||||||
|
EnvironmentOverrideColors bool
|
||||||
|
|
||||||
// Disable timestamp logging. useful when output is redirected to logging
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
// system that already adds timestamps.
|
// system that already adds timestamps.
|
||||||
DisableTimestamp bool
|
DisableTimestamp bool
|
||||||
@ -54,69 +56,135 @@ type TextFormatter struct {
|
|||||||
// be desired.
|
// be desired.
|
||||||
DisableSorting bool
|
DisableSorting bool
|
||||||
|
|
||||||
|
// The keys sorting function, when uninitialized it uses sort.Strings.
|
||||||
|
SortingFunc func([]string)
|
||||||
|
|
||||||
|
// Disables the truncation of the level text to 4 characters.
|
||||||
|
DisableLevelTruncation bool
|
||||||
|
|
||||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||||
QuoteEmptyFields bool
|
QuoteEmptyFields bool
|
||||||
|
|
||||||
// Whether the logger's out is to a terminal
|
// Whether the logger's out is to a terminal
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
|
|
||||||
sync.Once
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||||
|
// As an example:
|
||||||
|
// formatter := &TextFormatter{
|
||||||
|
// FieldMap: FieldMap{
|
||||||
|
// FieldKeyTime: "@timestamp",
|
||||||
|
// FieldKeyLevel: "@level",
|
||||||
|
// FieldKeyMsg: "@message"}}
|
||||||
|
FieldMap FieldMap
|
||||||
|
|
||||||
|
terminalInitOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) init(entry *Entry) {
|
func (f *TextFormatter) init(entry *Entry) {
|
||||||
if entry.Logger != nil {
|
if entry.Logger != nil {
|
||||||
f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
|
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||||
|
|
||||||
|
if f.isTerminal {
|
||||||
|
initTerminal(entry.Logger.Out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
|
func (f *TextFormatter) isColored() bool {
|
||||||
switch v := w.(type) {
|
isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
|
||||||
case *os.File:
|
|
||||||
return terminal.IsTerminal(int(v.Fd()))
|
if f.EnvironmentOverrideColors {
|
||||||
default:
|
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
|
||||||
return false
|
isColored = true
|
||||||
|
} else if ok && force == "0" {
|
||||||
|
isColored = false
|
||||||
|
} else if os.Getenv("CLICOLOR") == "0" {
|
||||||
|
isColored = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isColored && !f.DisableColors
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format renders a single log entry
|
// Format renders a single log entry
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
var b *bytes.Buffer
|
data := make(Fields)
|
||||||
keys := make([]string, 0, len(entry.Data))
|
for k, v := range entry.Data {
|
||||||
for k := range entry.Data {
|
data[k] = v
|
||||||
|
}
|
||||||
|
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||||
|
keys := make([]string, 0, len(data))
|
||||||
|
for k := range data {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !f.DisableSorting {
|
fixedKeys := make([]string, 0, 4+len(data))
|
||||||
sort.Strings(keys)
|
if !f.DisableTimestamp {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||||
}
|
}
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
|
||||||
|
if entry.Message != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
||||||
|
}
|
||||||
|
if entry.err != "" {
|
||||||
|
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||||
|
}
|
||||||
|
if entry.HasCaller() {
|
||||||
|
fixedKeys = append(fixedKeys,
|
||||||
|
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
if f.SortingFunc == nil {
|
||||||
|
sort.Strings(keys)
|
||||||
|
fixedKeys = append(fixedKeys, keys...)
|
||||||
|
} else {
|
||||||
|
if !f.isColored() {
|
||||||
|
fixedKeys = append(fixedKeys, keys...)
|
||||||
|
f.SortingFunc(fixedKeys)
|
||||||
|
} else {
|
||||||
|
f.SortingFunc(keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fixedKeys = append(fixedKeys, keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var b *bytes.Buffer
|
||||||
if entry.Buffer != nil {
|
if entry.Buffer != nil {
|
||||||
b = entry.Buffer
|
b = entry.Buffer
|
||||||
} else {
|
} else {
|
||||||
b = &bytes.Buffer{}
|
b = &bytes.Buffer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefixFieldClashes(entry.Data)
|
f.terminalInitOnce.Do(func() { f.init(entry) })
|
||||||
|
|
||||||
f.Do(func() { f.init(entry) })
|
|
||||||
|
|
||||||
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
timestampFormat := f.TimestampFormat
|
||||||
if timestampFormat == "" {
|
if timestampFormat == "" {
|
||||||
timestampFormat = defaultTimestampFormat
|
timestampFormat = defaultTimestampFormat
|
||||||
}
|
}
|
||||||
if isColored {
|
if f.isColored() {
|
||||||
f.printColored(b, entry, keys, timestampFormat)
|
f.printColored(b, entry, keys, data, timestampFormat)
|
||||||
} else {
|
} else {
|
||||||
if !f.DisableTimestamp {
|
for _, key := range fixedKeys {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
var value interface{}
|
||||||
|
switch {
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyTime):
|
||||||
|
value = entry.Time.Format(timestampFormat)
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyLevel):
|
||||||
|
value = entry.Level.String()
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyMsg):
|
||||||
|
value = entry.Message
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||||
|
value = entry.err
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||||
|
value = entry.Caller.Function
|
||||||
|
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||||
|
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||||
|
default:
|
||||||
|
value = data[key]
|
||||||
}
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, key, value)
|
||||||
if entry.Message != "" {
|
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
|
||||||
}
|
|
||||||
for _, key := range keys {
|
|
||||||
f.appendKeyValue(b, key, entry.Data[key])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +192,10 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
|
||||||
var levelColor int
|
var levelColor int
|
||||||
switch entry.Level {
|
switch entry.Level {
|
||||||
case DebugLevel:
|
case DebugLevel, TraceLevel:
|
||||||
levelColor = gray
|
levelColor = gray
|
||||||
case WarnLevel:
|
case WarnLevel:
|
||||||
levelColor = yellow
|
levelColor = yellow
|
||||||
@ -137,17 +205,31 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||||||
levelColor = blue
|
levelColor = blue
|
||||||
}
|
}
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
levelText := strings.ToUpper(entry.Level.String())
|
||||||
|
if !f.DisableLevelTruncation {
|
||||||
|
levelText = levelText[0:4]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a single newline if it already exists in the message to keep
|
||||||
|
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||||
|
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||||
|
|
||||||
|
caller := ""
|
||||||
|
|
||||||
|
if entry.HasCaller() {
|
||||||
|
caller = fmt.Sprintf("%s:%d %s()",
|
||||||
|
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
|
||||||
|
}
|
||||||
|
|
||||||
if f.DisableTimestamp {
|
if f.DisableTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
||||||
} else if !f.FullTimestamp {
|
} else if !f.FullTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
|
||||||
}
|
}
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := entry.Data[k]
|
v := data[k]
|
||||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
||||||
f.appendValue(b, v)
|
f.appendValue(b, v)
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
@ -24,6 +24,8 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
|||||||
var printFunc func(args ...interface{})
|
var printFunc func(args ...interface{})
|
||||||
|
|
||||||
switch level {
|
switch level {
|
||||||
|
case TraceLevel:
|
||||||
|
printFunc = entry.Trace
|
||||||
case DebugLevel:
|
case DebugLevel:
|
||||||
printFunc = entry.Debug
|
printFunc = entry.Debug
|
||||||
case InfoLevel:
|
case InfoLevel:
|
||||||
|
Loading…
Reference in New Issue
Block a user