diff --git a/cdre/cdrexporter.go b/cdre/cdrexporter.go index 33351c608..da8f64bd1 100644 --- a/cdre/cdrexporter.go +++ b/cdre/cdrexporter.go @@ -38,6 +38,7 @@ const ( METATAG = "metatag" CONCATENATED_CDRFIELD = "concatenated_cdrfield" COMBIMED = "combimed" + DATETIME = "datetime" HTTP_POST = "http_post" META_EXPORTID = "export_id" META_TIMENOW = "time_now" @@ -133,6 +134,23 @@ func (cdre *CdrExporter) maskedDestination(destination string) bool { return false } +func (cdre *CdrExporter) getDateTimeFieldVal(cdr *utils.StoredCdr, fltrRl, fieldRl *utils.RSRField, layout string) (string, error) { + if fieldRl == nil { + return "", nil + } + if fltrRl != nil && cdr.FieldAsString(&utils.RSRField{Id: fltrRl.Id}) != cdr.FieldAsString(fltrRl) { + return "", fmt.Errorf("Field: %s not matching filter rule %v", fltrRl.Id, fltrRl) + } + if len(layout) == 0 { + layout = time.RFC3339 + } + if dtFld, err := utils.ParseTimeDetectLayout(cdr.FieldAsString(fieldRl)); err != nil { + return "", err + } else { + return dtFld.Format(layout), nil + } +} + // Extracts the value specified by cfgHdr out of cdr func (cdre *CdrExporter) cdrFieldValue(cdr *utils.StoredCdr, fltrRl, rsrFld *utils.RSRField, layout string) (string, error) { if rsrFld == nil { @@ -141,6 +159,9 @@ func (cdre *CdrExporter) cdrFieldValue(cdr *utils.StoredCdr, fltrRl, rsrFld *uti if fltrRl != nil && cdr.FieldAsString(&utils.RSRField{Id: fltrRl.Id}) != cdr.FieldAsString(fltrRl) { return "", fmt.Errorf("Field: %s not matching filter rule %v", fltrRl.Id, fltrRl) } + if len(layout) == 0 { + layout = time.RFC3339 + } var cdrVal string switch rsrFld.Id { case COST_DETAILS: // Special case when we need to further extract cost_details out of logDb @@ -279,6 +300,8 @@ func (cdre *CdrExporter) processCdr(cdr *utils.StoredCdr) error { outVal = cfgFld.Value case utils.CDRFIELD: outVal, err = cdre.cdrFieldValue(cdr, cfgFld.Filter, cfgFld.ValueAsRSRField(), cfgFld.Layout) + case DATETIME: + outVal, err = cdre.getDateTimeFieldVal(cdr, cfgFld.Filter, cfgFld.ValueAsRSRField(), cfgFld.Layout) case HTTP_POST: var outValByte []byte if outValByte, err = utils.HttpJsonPost(cfgFld.Value, cdre.httpSkipTlsCheck, cdr); err == nil { diff --git a/cdre/cdrexporter_test.go b/cdre/cdrexporter_test.go index 3af4faaf3..c3918b33f 100644 --- a/cdre/cdrexporter_test.go +++ b/cdre/cdrexporter_test.go @@ -70,6 +70,29 @@ func TestCdreGetCombimedCdrFieldVal(t *testing.T) { } } +func TestGetDateTimeFieldVal(t *testing.T) { + cdreTst := new(CdrExporter) + cdrTst := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1", + ReqType: "rated", Direction: "*out", Tenant: "cgrates.org", + Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Unix(1383813745, 0).UTC(), AnswerTime: time.Unix(1383813746, 0).UTC(), + Usage: time.Duration(10) * time.Second, MediationRunId: utils.DEFAULT_RUNID, Cost: 1.01, + ExtraFields: map[string]string{"stop_time": "2014-06-11 19:19:00 +0000 UTC", "fieldextr2": "valextr2"}} + if cdrVal, err := cdreTst.getDateTimeFieldVal(cdrTst, nil, &utils.RSRField{Id: "stop_time"}, "2006-01-02 15:04:05"); err != nil { + t.Error(err) + } else if cdrVal != "2014-06-11 19:19:00" { + t.Error("Expecting: 2014-06-11 19:19:00, got: ", cdrVal) + } + // Test filter + fltrRule, _ := utils.NewRSRField("~tenant:s/(.+)/itsyscom.com/") + if _, err := cdreTst.getDateTimeFieldVal(cdrTst, fltrRule, &utils.RSRField{Id: "stop_time"}, "2006-01-02 15:04:05"); err == nil { + t.Error(err) + } + // Test time parse error + if _, err := cdreTst.getDateTimeFieldVal(cdrTst, nil, &utils.RSRField{Id: "fieldextr2"}, "2006-01-02 15:04:05"); err == nil { + t.Error("Should give error here, got none.") + } +} + func TestCdreCdrFieldValue(t *testing.T) { cdre := new(CdrExporter) cdr := &utils.StoredCdr{CgrId: utils.Sha1("dsafdsaf", time.Unix(1383813745, 0).UTC().String()), TOR: utils.VOICE, AccId: "dsafdsaf", CdrHost: "192.168.1.1",