Search code examples
elasticsearchelasticsearch-painlesskibana-7

Painless script to get time difference between two logs entries separated by a unique ID


I am trying to get time difference between two log entries like RequestExecuted and RequestReceived with a filed name MessageIdentifier. These valuse are linked by unique id named TransactionId. Below is my code to do the logic.

int timetaken=0;      
int start=0;      
String TransactionId;      
int end=0;   

for(int i = 0; i < 10; ++i){        
    if (doc['dissect.MessageIdentifier'].value[i]=='RequestReceived') {          
        start=params._source.dissect.timestamp[i];          
        TransactionId=params._source.dissect.TransactionId[i];
     }        
    if( doc['dissect.MessageIdentifier'].value[i] =='RequestExecuted' 
        && params._source.dissect.TransactionId == TransactionId) {          
            end=params._source.dissect.timestamp[i];          
            timetaken = end - start; 
            return timetaken;
    }
}

When i compile my painless script it gives me an error:

lang": "painless",
    "caused_by": {
     "type": "illegal_argument_exception",
     "reason": "Attempting to address a non-array-like type [java.lang.String] as an array."

Here is the index snippet:

enter image description here

Your help will be highly obliged.


Solution

  • Presuming your dissect field is an array of nested objects you can do the following:

    Create index

    PUT dissect
    {
      "mappings": {
        "properties": {
           "dissect" : {
             "type": "nested", 
              "properties" : {
                "MessageIdentifier" : {
                  "type" : "text",
                  "fielddata": true,
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                },
                "TransationId" : {
                  "type" : "text",
                  "fielddata": true,
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                },
                "timestamp" : {
                  "type" : "date"
                }
              }
            }
        }
      }
    }
    

    Sync a sample

    POST dissect/_doc
    {
      "dissect": [
        {
          "MessageIdentifier": "abc",
          "timestamp": 200,
          "TransationId": "xyz"
        },
        {
          "MessageIdentifier": "RequestReceived",
          "timestamp": 300,
          "TransationId": "xyz"
        },
        {
          "MessageIdentifier": "RequestExecuted",
          "timestamp": 400,
          "TransationId": "xyz"
        }
      ]
    }
    

    Run your script field

    GET dissect/_search
    {
      "script_fields": {
        "timetaken": {
          "script": {
            "source": """
            int timetaken = 0;      
            int start = 0;      
            String TransactionId;      
            int end = 0;   
    
            for (def dissect_item : params._source['dissect']) {
              if (dissect_item['MessageIdentifier'] == 'RequestReceived') {          
                    start = dissect_item['timestamp'];          
                    TransactionId = dissect_item['TransactionId'];
                }
    
                if( dissect_item['MessageIdentifier'] =='RequestExecuted' 
                    && dissect_item['TransactionId'] == TransactionId) {          
                        end = dissect_item['timestamp'];          
                        timetaken = end - start; 
                        return timetaken;
                }
            }
            """
          }
        }
      }
    }
    

    yielding

    [
      {
        "_index":"dissect",
        "_type":"_doc",
        "_id":"_v7u43EBW-D5QnrWmjtM",
        "_score":1.0,
        "fields":{
          "timetaken":[
            100              <-----
          ]
        }
      }
    ]
    

    Key takeaway: you don't wanna be iterating over a hard-coded length of 10 but instead as for (def dissect_item : params._source['dissect'])