diff --git a/cmd/goflow2/mapping.yaml b/cmd/goflow2/mapping.yaml index ca330cb..bf87dd3 100644 --- a/cmd/goflow2/mapping.yaml +++ b/cmd/goflow2/mapping.yaml @@ -43,6 +43,8 @@ formatter: - name: csum index: 999 type: varint + render: + time_received_ns: datetimenano # Decoder mappings ipfix: mapping: diff --git a/producer/proto/render.go b/producer/proto/render.go index 63c85e2..07e9989 100644 --- a/producer/proto/render.go +++ b/producer/proto/render.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "net" "net/netip" + "time" ) type RenderFunc func(msg *ProtoProducerMessage, fieldName string, data interface{}) interface{} @@ -12,22 +13,26 @@ type RenderFunc func(msg *ProtoProducerMessage, fieldName string, data interface type RendererID string const ( - RendererNone RendererID = "none" - RendererIP RendererID = "ip" - RendererMac RendererID = "mac" - RendererEtype RendererID = "etype" - RendererProto RendererID = "proto" - RendererType RendererID = "type" - RendererNetwork RendererID = "network" + RendererNone RendererID = "none" + RendererIP RendererID = "ip" + RendererMac RendererID = "mac" + RendererEtype RendererID = "etype" + RendererProto RendererID = "proto" + RendererType RendererID = "type" + RendererNetwork RendererID = "network" + RendererDateTime RendererID = "datetime" + RendererDateTimeNano RendererID = "datetimenano" ) var ( renderers = map[RendererID]RenderFunc{ - RendererNone: NilRenderer, - RendererIP: IPRenderer, - RendererMac: MacRenderer, - RendererEtype: EtypeRenderer, - RendererProto: ProtoRenderer, + RendererNone: NilRenderer, + RendererIP: IPRenderer, + RendererMac: MacRenderer, + RendererEtype: EtypeRenderer, + RendererProto: ProtoRenderer, + RendererDateTime: DateTimeRenderer, + RendererDateTimeNano: DateTimeNanoRenderer, } defaultRenderers = map[string]RenderFunc{ @@ -90,6 +95,34 @@ func NilRenderer(msg *ProtoProducerMessage, fieldName string, data interface{}) return data } +func DateTimeRenderer(msg *ProtoProducerMessage, fieldName string, data interface{}) interface{} { + if dataC, ok := data.(uint64); ok { + ts := time.Unix(int64(dataC), 0).UTC() + return ts.Format(time.RFC3339Nano) + } else if dataC, ok := data.(int64); ok { + ts := time.Unix(dataC, 0).UTC() + return ts.Format(time.RFC3339Nano) + } else if dataC, ok := data.(uint32); ok { + ts := time.Unix(int64(dataC), 0).UTC() + return ts.Format(time.RFC3339Nano) + } else if dataC, ok := data.(int32); ok { + ts := time.Unix(int64(dataC), 0).UTC() + return ts.Format(time.RFC3339Nano) + } + return NilRenderer(msg, fieldName, data) +} + +func DateTimeNanoRenderer(msg *ProtoProducerMessage, fieldName string, data interface{}) interface{} { + if dataC, ok := data.(uint64); ok { + ts := time.Unix(int64(dataC)/1e9, int64(dataC)%1e9).UTC() + return ts.Format(time.RFC3339Nano) + } else if dataC, ok := data.(int64); ok { + ts := time.Unix(dataC/1e9, dataC%1e9).UTC() + return ts.Format(time.RFC3339Nano) + } + return NilRenderer(msg, fieldName, data) +} + func MacRenderer(msg *ProtoProducerMessage, fieldName string, data interface{}) interface{} { if dataC, ok := data.(uint64); ok { var mac [8]byte