package binarylog
import (
binlogpb
)
type callIDGenerator struct {
id uint64
}
func ( *callIDGenerator) () uint64 {
:= atomic.AddUint64(&.id, 1)
return
}
func ( *callIDGenerator) () {
.id = 0
}
var idGen callIDGenerator
type MethodLogger interface {
Log(LogEntryConfig)
}
type TruncatingMethodLogger struct {
headerMaxLen, messageMaxLen uint64
callID uint64
idWithinCallGen *callIDGenerator
sink Sink
}
func (, uint64) *TruncatingMethodLogger {
return &TruncatingMethodLogger{
headerMaxLen: ,
messageMaxLen: ,
callID: idGen.next(),
idWithinCallGen: &callIDGenerator{},
sink: DefaultSink,
}
}
func ( *TruncatingMethodLogger) ( LogEntryConfig) *binlogpb.GrpcLogEntry {
:= .toProto()
, := ptypes.TimestampProto(time.Now())
.Timestamp =
.CallId = .callID
.SequenceIdWithinCall = .idWithinCallGen.next()
switch pay := .Payload.(type) {
case *binlogpb.GrpcLogEntry_ClientHeader:
.PayloadTruncated = .truncateMetadata(.ClientHeader.GetMetadata())
case *binlogpb.GrpcLogEntry_ServerHeader:
.PayloadTruncated = .truncateMetadata(.ServerHeader.GetMetadata())
case *binlogpb.GrpcLogEntry_Message:
.PayloadTruncated = .truncateMessage(.Message)
}
return
}
func ( *TruncatingMethodLogger) ( LogEntryConfig) {
.sink.Write(.Build())
}
func ( *TruncatingMethodLogger) ( *binlogpb.Metadata) ( bool) {
if .headerMaxLen == maxUInt {
return false
}
var (
= .headerMaxLen
int
)
for ; < len(.Entry); ++ {
:= .Entry[]
if .Key == "grpc-trace-bin" {
continue
}
:= uint64(len(.GetKey())) + uint64(len(.GetValue()))
if > {
break
}
-=
}
= < len(.Entry)
.Entry = .Entry[:]
return
}
func ( *TruncatingMethodLogger) ( *binlogpb.Message) ( bool) {
if .messageMaxLen == maxUInt {
return false
}
if .messageMaxLen >= uint64(len(.Data)) {
return false
}
.Data = .Data[:.messageMaxLen]
return true
}
type LogEntryConfig interface {
toProto() *binlogpb.GrpcLogEntry
}
type ClientHeader struct {
OnClientSide bool
Header metadata.MD
MethodName string
Authority string
Timeout time.Duration
PeerAddr net.Addr
}
func ( *ClientHeader) () *binlogpb.GrpcLogEntry {
:= &binlogpb.ClientHeader{
Metadata: mdToMetadataProto(.Header),
MethodName: .MethodName,
Authority: .Authority,
}
if .Timeout > 0 {
.Timeout = ptypes.DurationProto(.Timeout)
}
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
Payload: &binlogpb.GrpcLogEntry_ClientHeader{
ClientHeader: ,
},
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
if .PeerAddr != nil {
.Peer = addrToProto(.PeerAddr)
}
return
}
type ServerHeader struct {
OnClientSide bool
Header metadata.MD
PeerAddr net.Addr
}
func ( *ServerHeader) () *binlogpb.GrpcLogEntry {
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
Payload: &binlogpb.GrpcLogEntry_ServerHeader{
ServerHeader: &binlogpb.ServerHeader{
Metadata: mdToMetadataProto(.Header),
},
},
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
if .PeerAddr != nil {
.Peer = addrToProto(.PeerAddr)
}
return
}
type ClientMessage struct {
OnClientSide bool
Message interface{}
}
func ( *ClientMessage) () *binlogpb.GrpcLogEntry {
var (
[]byte
error
)
if , := .Message.(proto.Message); {
, = proto.Marshal()
if != nil {
grpclogLogger.Infof("binarylogging: failed to marshal proto message: %v", )
}
} else if , := .Message.([]byte); {
=
} else {
grpclogLogger.Infof("binarylogging: message to log is neither proto.message nor []byte")
}
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE,
Payload: &binlogpb.GrpcLogEntry_Message{
Message: &binlogpb.Message{
Length: uint32(len()),
Data: ,
},
},
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
return
}
type ServerMessage struct {
OnClientSide bool
Message interface{}
}
func ( *ServerMessage) () *binlogpb.GrpcLogEntry {
var (
[]byte
error
)
if , := .Message.(proto.Message); {
, = proto.Marshal()
if != nil {
grpclogLogger.Infof("binarylogging: failed to marshal proto message: %v", )
}
} else if , := .Message.([]byte); {
=
} else {
grpclogLogger.Infof("binarylogging: message to log is neither proto.message nor []byte")
}
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE,
Payload: &binlogpb.GrpcLogEntry_Message{
Message: &binlogpb.Message{
Length: uint32(len()),
Data: ,
},
},
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
return
}
type ClientHalfClose struct {
OnClientSide bool
}
func ( *ClientHalfClose) () *binlogpb.GrpcLogEntry {
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE,
Payload: nil,
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
return
}
type ServerTrailer struct {
OnClientSide bool
Trailer metadata.MD
Err error
PeerAddr net.Addr
}
func ( *ServerTrailer) () *binlogpb.GrpcLogEntry {
, := status.FromError(.Err)
if ! {
grpclogLogger.Info("binarylogging: error in trailer is not a status error")
}
var (
[]byte
error
)
:= .Proto()
if != nil && len(.Details) != 0 {
, = proto.Marshal()
if != nil {
grpclogLogger.Infof("binarylogging: failed to marshal status proto: %v", )
}
}
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
Payload: &binlogpb.GrpcLogEntry_Trailer{
Trailer: &binlogpb.Trailer{
Metadata: mdToMetadataProto(.Trailer),
StatusCode: uint32(.Code()),
StatusMessage: .Message(),
StatusDetails: ,
},
},
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
if .PeerAddr != nil {
.Peer = addrToProto(.PeerAddr)
}
return
}
type Cancel struct {
OnClientSide bool
}
func ( *Cancel) () *binlogpb.GrpcLogEntry {
:= &binlogpb.GrpcLogEntry{
Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CANCEL,
Payload: nil,
}
if .OnClientSide {
.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT
} else {
.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER
}
return
}
func ( string) bool {
switch {
case "lb-token", ":path", ":authority", "content-encoding", "content-type", "user-agent", "te":
return true
case "grpc-trace-bin":
return false
}
return strings.HasPrefix(, "grpc-")
}
func ( metadata.MD) *binlogpb.Metadata {
:= &binlogpb.Metadata{}
for , := range {
if metadataKeyOmit() {
continue
}
for , := range {
.Entry = append(.Entry,
&binlogpb.MetadataEntry{
Key: ,
Value: []byte(),
},
)
}
}
return
}
func ( net.Addr) *binlogpb.Address {
:= &binlogpb.Address{}
switch a := .(type) {
case *net.TCPAddr:
if .IP.To4() != nil {
.Type = binlogpb.Address_TYPE_IPV4
} else if .IP.To16() != nil {
.Type = binlogpb.Address_TYPE_IPV6
} else {
.Type = binlogpb.Address_TYPE_UNKNOWN
break
}
.Address = .IP.String()
.IpPort = uint32(.Port)
case *net.UnixAddr:
.Type = binlogpb.Address_TYPE_UNIX
.Address = .String()
default:
.Type = binlogpb.Address_TYPE_UNKNOWN
}
return
}