Splunk Search

How to use eval to sum a large set of fields with field name matching a pattern?

driekhof
Path Finder

I have several fields like this:

types.events.1
types.events.2
types.events.3
etc

I can use eval to sum them like this

eval totalDomainEvents = 'types.events.1' + 'types.events.2' + 'types.events.3' + etc

But I have a lot of these fields. Is there a way to do something like this?

eval totalDomainEvents = sum('types.events.*')

That doesn't work, but hopefully conveys the idea. I'd like to avoid including every field I want included in the eval if possible by just using some kind of wildcard matching to indicate the fields to include in the eval.

0 Karma

driekhof
Path Finder

I also noticed that when I'm trying to sum a large number of fields with eval, I get erroneous values. For example, the total is correct as long as I'm summing 2 or 3 fields, but as I try to sum more and more the total starts missing some fields, and eventually around 20 fields the total becomes less that some individual fields.

0 Karma

DalJeanis
Legend

Here's some run-anywhere code that shows you an example after generating random data...

| makeresults count=5
| eval "types.events.1" = tonumber(substr(tostring(random()),1,2))
| eval "types.events.2" = tonumber(substr(tostring(random()),1,3))
| eval "types.events.3" = tonumber(substr(tostring(random()),2,2))
| table types.events.*
| eventstats sum("types.events."*) as sum.*
| addtotals row=f col=t

producing this...

types.events.1  types.events.2  types.events.3  sum.1  sum.2  sum.3  
18              651             28              132    2139   243    
67              169             49              132    2139   243    
16              440             49              132    2139   243    
11              149             60              132    2139   243    
20              730             57              132    2139   243    
132             2139            243             660    10695  1215   

...but you probably wanted this

| makeresults count=5
| eval "types.events.1" = tonumber(substr(tostring(random()),1,2))
| eval "types.events.2" = tonumber(substr(tostring(random()),1,3))
| eval "types.events.3" = tonumber(substr(tostring(random()),2,2))
| table types.events.*    | addtotals row=t col=f fieldname="types.events.total" "types.events.*"

... which produces this ...

types.events.1  types.events.2  types.events.3  types.events.total      
16              380             87              483                     
18              168             42              228                     
15              134             49              198                     
10              167             10              187                     
15              511             16              542  

driekhof
Path Finder

Thanks. I'm trying to get that to feed into a timechart, but not having any luck so far. I've got events coming in every second, and I'd like to sum them over 1 minute spans.

0 Karma

DalJeanis
Legend

You need _time for that, which is a different "event faker" command. This generates test data...

| gentimes start="01/25/2017:23:00:00" end="01/27/2017:01:00:00" increment=23m 
| streamstats count as baseEvent | eval series="A"
| append[| gentimes start="01/26/2017:03:00:00" end="01/26/2017:21:00:00" increment=47m | streamstats count as baseEvent | eval series="B"]
| append[| gentimes start="01/26/2017:01:17:00" end="01/26/2017:23:18:00" increment=21m | streamstats count as baseEvent | eval series="C"]
 | eval _time=starttime
 | eval "types.events.1" = tonumber(substr(tostring(random()),1,2))
 | eval "types.events.2" = tonumber(substr(tostring(random()),1,3))
 | eval "types.events.3" = tonumber(substr(tostring(random()),2,2))
 | table _time types.events.*    

... this adds the totals...

| addtotals row=t col=f fieldname="types.events.total" "types.events.*"

... then this timecharts the results...

| timechart span=1h sum("types.events.*") as "types.events.*"

That's spanned at the 1h level because my transaction faker is set up to generate transactions every few minutes across a few days, but you can use it however you want.

0 Karma

niketn
Legend

You can use foreach command for template search
(Refer to documentation: https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Foreach)

<Your Base Search>| foreach "types.events."* [eval totalDomainResults=totalDomainResults + '<<FIELD>>']

Both the fieldname as well as field string <<FIELD>> need to be escaped with double quotes and single quotes respectively, since your field name contains special character dot (.) which is used for concatenation in eval statements.

____________________________________________
| makeresults | eval message= "Happy Splunking!!!"
0 Karma

driekhof
Path Finder

I tried this but nothing is returned for totalDomainResults. Am I supposed to substitute something for FIELD?

0 Karma

somesoni2
Revered Legend

Just declare a field totalDomainResults before foreach command, like this

<Your Base Search> | eval totalDomainResults=0 | foreach "types.events.*" [eval totalDomainResults=totalDomainResults + '<<FIELD>>']
Get Updates on the Splunk Community!

Continuing Innovation & New Integrations Unlock Full Stack Observability For Your ...

You’ve probably heard the latest about AppDynamics joining the Splunk Observability portfolio, deepening our ...

Monitoring Amazon Elastic Kubernetes Service (EKS)

As we’ve seen, integrating Kubernetes environments with Splunk Observability Cloud is a quick and easy way to ...

Cloud Platform & Enterprise: Classic Dashboard Export Feature Deprecation

As of Splunk Cloud Platform 9.3.2408 and Splunk Enterprise 9.4, classic dashboard export features are now ...