Alerting

Getting error Error in 'eval' command: The expression is malformed. An unexpected character is reached at ')'.

loveforsplunk
Explorer

I have the below search.. at times it is working and at times it is not .. not sure why. Can some one please help.

index=index host=host source="source" "keyword" | head 1| stats count(eval(searchmatch("keyword"))) AS searchmatchresult| eval value=if((searchmatchresult>0), "no alert", [search index=index host=host keyword1| where keyword1<5 | head 1 | return $keyword1]) | stats count by value| where value<5 AND value!="no alert"

Also, is there a possibility to check if the value of keyword1 remains below 5 for 10 minutes then only that will throw an alert ?

Tags (1)
0 Karma
1 Solution

DalJeanis
Legend

@loveforsplunk - If you state clearly what you are trying to do-- just the end result, not the method -- then we can spend a lot less time reviewing the complexity of your particular solution. @yuanli deserves LOTS of upvotes for his work untangling the intentions of your code.

Okay, my guess is that all that code is an attempt to do the following:

If there is NO match on "keyword", then check for the last value of field keyword1 being less than 5, and if so return the numeric value of field keyword1.

Just some general splunk coding advice - try NOT to treat SPL as a programming language, because it is really inefficient when used that way. "I only want to search for X if A and B are true" is something you should avoid. Think more in terms of "give me all the records that are like THIS, chew them up THIS way for me, and then I'll decide what parts I need to use."

Here's how I'd answer this particular need: get all the records in the last N minutes for "keyword" and for "keyword1", then stats them to get the values you are interested in, and finally do a single compare to see if we need an alert. I've prepared three versions based on your potential needs.

This version gets the value of the very last record with keyword1 and checks if it is under 5. Remember, splunk returns records with the most recent first...

earliest=-5m index=foo host=bar source=baz ("keyword" OR keyword1=*)
| stats count(eval(searchmatch("keyword0")) as k0, first(keyword1) as k1
| fillnull value=0 k0 k1
| where k0=0 and k1<5

This version checks to see if the highest value of keyword1 in the last 5 minutes is under 5...

earliest=-5m index=foo host=bar source=baz ("keyword" OR "keyword1")
| stats count(eval(searchmatch("keyword0")) as k0, max(keyword1) as k1
| fillnull value=0 k0 k1
| where k0=0 and k1<5

Use this version ONLY if there are expected to be a lot of "keyword" records in 5 minutes, or if you absolutely need to use different timeframes for keyword and keyword1, for instance 5m and 10m respectively.

earliest=-5m index=foo host=bar source=baz "keyword" 
| head 1 
| stats count as k0
| fillnull value=0 k0 k1
| append 
    [ search  earliest=-10m index=foo host=bar source=baz keyword1=*
    | stats max(keyword1) as k1 
    | fillnull value=0 k0 k1
    ]
| stats max(*) as *
| where k0=0 and k1<5

View solution in original post

0 Karma

DalJeanis
Legend

@loveforsplunk - If you state clearly what you are trying to do-- just the end result, not the method -- then we can spend a lot less time reviewing the complexity of your particular solution. @yuanli deserves LOTS of upvotes for his work untangling the intentions of your code.

Okay, my guess is that all that code is an attempt to do the following:

If there is NO match on "keyword", then check for the last value of field keyword1 being less than 5, and if so return the numeric value of field keyword1.

Just some general splunk coding advice - try NOT to treat SPL as a programming language, because it is really inefficient when used that way. "I only want to search for X if A and B are true" is something you should avoid. Think more in terms of "give me all the records that are like THIS, chew them up THIS way for me, and then I'll decide what parts I need to use."

Here's how I'd answer this particular need: get all the records in the last N minutes for "keyword" and for "keyword1", then stats them to get the values you are interested in, and finally do a single compare to see if we need an alert. I've prepared three versions based on your potential needs.

This version gets the value of the very last record with keyword1 and checks if it is under 5. Remember, splunk returns records with the most recent first...

earliest=-5m index=foo host=bar source=baz ("keyword" OR keyword1=*)
| stats count(eval(searchmatch("keyword0")) as k0, first(keyword1) as k1
| fillnull value=0 k0 k1
| where k0=0 and k1<5

This version checks to see if the highest value of keyword1 in the last 5 minutes is under 5...

earliest=-5m index=foo host=bar source=baz ("keyword" OR "keyword1")
| stats count(eval(searchmatch("keyword0")) as k0, max(keyword1) as k1
| fillnull value=0 k0 k1
| where k0=0 and k1<5

Use this version ONLY if there are expected to be a lot of "keyword" records in 5 minutes, or if you absolutely need to use different timeframes for keyword and keyword1, for instance 5m and 10m respectively.

earliest=-5m index=foo host=bar source=baz "keyword" 
| head 1 
| stats count as k0
| fillnull value=0 k0 k1
| append 
    [ search  earliest=-10m index=foo host=bar source=baz keyword1=*
    | stats max(keyword1) as k1 
    | fillnull value=0 k0 k1
    ]
| stats max(*) as *
| where k0=0 and k1<5
0 Karma

loveforsplunk
Explorer

oh wow .. I never thought in so simple way. Thank u so much. If I have support from people like you then I think I will learn splunk pretty quickly 😄 . Can u please tell me why have u used this fillnull value=0 k0 k1.. what does it do

loveforsplunk
Explorer

oh ok .. if I am not wrong , it will fill any null value with 0 for k1 and k0

DalJeanis
Legend

@loveforsplunk - Completely correct. And you were correct to ask, because logically, it is not needed for BOTH fields in every place I have used it. Sometimes, logically, one of those values MUST have been filled in. But I was just being a bit lazy mentally, so I made completely sure it would be filled in any place I wanted it to be.

Please upvote @yuanliu also, he did a lot of work on your behalf, his answer was very insightful and helpful, and I probably would not have gotten to the answer you needed nearly as fast or as completely as I did without him blazing the way.

0 Karma

loveforsplunk
Explorer

Yes I did reward him for his help as well . He did a great help to me . Also thank you . The only change I made was to remove the fillnull command as I wanted to trigger my alert for results >0 . So in this case it was assigning 0 to my values and was creating a row in the stats for which I was getting false alerts.
Hopefully and finally I think my query and alert got completed and mission is successful 😉 . Thank you both @DalJeanis and @yuanliu.

0 Karma

yuanliu
SplunkTrust
SplunkTrust

A subsearch cannot be used in assignment. I can kind of guess what you try to do but you need to explain the intention if the following is not what you need: If "keyword" is found in the first record, you want no return ("no alert"); otherwise you want to return the histogram of numeric values of keyword1 but only if that value is less than 5. Several additional assumptions:

  • "keyword1" is both a literal in events and must be a numeric field that is already extracted
  • Regardless of what "keyword" is, I cannot imagine why you want to do count(eval(searchmatch("keyword"))) then test if this count>0. Because index=index host=host source="source" "keyword" has already determined that if there is no match, the count won't even happen.
  • Similarly, the last filter where value<5 AND value!="no alert" seems redundant because all previous results precludes the opposite.
  • Because keyword1 is already extracted as a numeric value, index=index host=host keyword1<5 will do exactly the same as index=index host=host keyword1| where keyword1<5, only faster.
  • Lastly, I cannot figure out the intention of the second head 1 (inside the subsearch) followed by stats count by value because the two head 1 will limit output to only one or zero. I will assume that your intention is to actually perform count by value.

If my understanding of the intentions is correct, the following should work:

index=index host=host (source="source" "keyword") OR (keyword1<5)
 | eventstats count by keyword1
 | eventstats count(eval(searchmatch("keyword"))) AS searchmatchresult
 | where searchmatchresult=0
 | table count keyword1

DalJeanis
Legend

@yuanliu - upvote for a very nice attempt to interpret and debug the existing code.

You were completely right that the final stats and the second head 1 commands were incompatible, you just jumped the other way to resolve the conflict.

If you read only the very last line of the original post, you will see what the OP is really trying to get to - if there are no records with keyword, and also keyword1 is below 5 for five minutes, then and only then splunk should throw an alert.

Unfortunately, we cannot constrain the data pull on keyword1 to those values less than 5, because an alert should NOT be thrown if there was a record with keyword1 >=5 in that period of time.

In light of this, you can revise and simplify your code and repost when you get a chance.

0 Karma
Get Updates on the Splunk Community!

.conf24 | Day 0

Hello Splunk Community! My name is Chris, and I'm based in Canberra, Australia's capital, and I travelled for ...

Enhance Security Visibility with Splunk Enterprise Security 7.1 through Threat ...

 (view in My Videos)Struggling with alert fatigue, lack of context, and prioritization around security ...

Troubleshooting the OpenTelemetry Collector

  In this tech talk, you’ll learn how to troubleshoot the OpenTelemetry collector - from checking the ...