Learn Splunk in 10 DaysDay 4: Fields and Filtering

Day 4: Fields and Filtering

What You Will Learn Today

  • Types of fields and how they are extracted
  • Creating fields with the eval command
  • Filtering with the where command
  • Extracting fields with the rex command
  • Field aliases and calculated fields

Types of Fields

Splunk fields fall into two broad categories: default fields and extracted fields.

flowchart TB
    subgraph Fields["Field Types"]
        Default["Default Fields<br>_time, host, source,<br>sourcetype, _raw"]
        Extracted["Extracted Fields<br>Automatic: status, user<br>Manual: rex, erex"]
        Calculated["Calculated Fields<br>Created with eval"]
    end
    style Default fill:#3b82f6,color:#fff
    style Extracted fill:#22c55e,color:#fff
    style Calculated fill:#f59e0b,color:#fff

Default Fields

Field Description
_time Event timestamp
_raw Raw event data
host The host that generated the data
source The data source (file path, etc.)
sourcetype The data type
index The destination index
_indextime The time the event was indexed
linecount Number of lines in the event

Automatic Field Extraction

Splunk automatically extracts fields from key=value patterns.

2026-01-30 10:00:01 status=200 user=alice duration=0.023

From the log above, status, user, and duration are automatically extracted as fields.


The eval Command

Use eval to create new fields or transform existing ones.

Basic Usage

index=main
| eval response_time_ms = duration * 1000
| eval status_category = if(status >= 400, "Error", "OK")
| table _time, status, status_category, duration, response_time_ms

eval Functions

String Functions

| eval lower_user = lower(user)
| eval upper_host = upper(host)
| eval greeting = "Hello, " . user    # String concatenation
| eval domain = replace(email, ".*@", "")
| eval length = len(message)
| eval first3 = substr(uri, 1, 3)
Function Description Example
lower(x) Convert to lowercase lower("ABC") -> "abc"
upper(x) Convert to uppercase upper("abc") -> "ABC"
len(x) String length len("hello") -> 5
substr(x,s,e) Substring substr("hello",1,3) -> "hel"
replace(x,r,n) Regex replacement replace(ip, "\.\d+$", ".0")
trim(x) Strip whitespace trim(" abc ") -> "abc"

Numeric Functions

| eval rounded = round(duration, 2)
| eval absolute = abs(difference)
| eval power = pow(2, 10)
| eval log_value = log(count, 10)

Conditional Functions

# if
| eval severity = if(status >= 500, "Critical", "Normal")

# case
| eval severity = case(
    status >= 500, "Critical",
    status >= 400, "Warning",
    status >= 300, "Redirect",
    1=1, "OK"
)

# coalesce (returns the first non-null value)
| eval display_name = coalesce(full_name, username, "Unknown")

# null check
| eval has_error = if(isnull(error_message), "No", "Yes")

Date/Time Functions

| eval event_date = strftime(_time, "%Y-%m-%d")
| eval event_hour = strftime(_time, "%H")
| eval day_of_week = strftime(_time, "%A")
| eval epoch = strptime("2026-01-30", "%Y-%m-%d")
| eval elapsed = now() - _time
Function Description
strftime(_time, fmt) Format a timestamp as a string
strptime(str, fmt) Parse a string into a timestamp
now() Current epoch time
relative_time(t, offset) Calculate a relative time

The where Command

Use where for advanced filtering with eval expressions.

# Basic comparison
index=main
| where status >= 400

# String comparison (where is case-sensitive)
index=main
| where user = "alice"

# Filtering with functions
index=main
| where like(uri, "/api/%")
| where len(user) > 3
| where isnotnull(error_message)

# Regex matching
index=main
| where match(uri, "^/api/v[0-9]+/")

search vs where

Comparison search where
Position Before or after the pipe After the pipe only
Case sensitivity Case-insensitive Case-sensitive
Wildcards Uses * Uses like()
eval functions Not available Available
Speed Faster Slightly slower
# search (keyword search, case-insensitive)
index=main
| search user=alice status>400

# where (eval expression, case-sensitive)
index=main
| where user="alice" AND status > 400

The rex Command

Use rex to extract fields with regular expressions.

# Extract an IP address
index=main
| rex field=_raw "(?P<ip_address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
| table _time, ip_address

# Extract an email address
index=main
| rex field=_raw "(?P<email>[\w.+-]+@[\w-]+\.[\w.]+)"
| table _time, email

# Extract path parameters from a URI
index=main
| rex field=uri "/api/(?P<api_version>v\d+)/(?P<resource>\w+)"
| table _time, api_version, resource

# Extract multiple named groups at once
index=main
| rex field=_raw "user=(?P<user>\w+).*status=(?P<status>\d+)"

Regex Syntax Reference

Pattern Description Matches
\d Digit 0-9
\w Word character a-z, 0-9, _
\s Whitespace Space, tab
. Any single character Anything
+ One or more \d+ -> 123
* Zero or more \d* -> "" or 123
? Zero or one \d? -> "" or 1
(?P<name>...) Named capture group Extracted as a field

rex mode=sed

Use sed syntax to replace strings in place.

# Mask IP addresses
index=main
| rex mode=sed field=_raw "s/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/xxx.xxx.xxx.xxx/g"

Field Aliases and Calculated Fields

Configuring in props.conf

# props.conf
[my_sourcetype]
# Field aliases
FIELDALIAS-src = src_ip AS source_ip
FIELDALIAS-dst = dst_ip AS dest_ip

# Calculated fields
EVAL-response_time_ms = response_time * 1000
EVAL-severity = case(status >= 500, "critical", status >= 400, "warning", 1=1, "info")

Key point: Field aliases and calculated fields are applied automatically at search time, so you do not need to write eval statements in every query.


Hands-On: Log Analysis Queries

# 1. Classify response times
index=main sourcetype=access_combined
| eval response_class = case(
    response_time < 0.1, "Fast",
    response_time < 1.0, "Normal",
    response_time < 5.0, "Slow",
    1=1, "Critical"
)
| stats count by response_class
| sort response_class

# 2. Error rate by hour of day
index=main sourcetype=access_combined
| eval hour = strftime(_time, "%H")
| eval is_error = if(status >= 400, 1, 0)
| stats avg(is_error) AS error_rate by hour
| eval error_rate_pct = round(error_rate * 100, 2)
| table hour, error_rate_pct
| sort hour

# 3. Extract browser from user agent
index=main sourcetype=access_combined
| rex field=useragent "(?P<browser>Chrome|Firefox|Safari|Edge|Opera)"
| stats count by browser
| sort -count

# 4. Subnet analysis from IP addresses
index=main sourcetype=access_combined
| rex field=clientip "(?P<subnet>\d+\.\d+\.\d+)\.\d+"
| eval subnet = subnet . ".0/24"
| stats count by subnet
| sort -count
| head 10

Summary

Concept Description
Default fields _time, host, source, sourcetype
eval Create and transform fields
where Filter using eval expressions
rex Extract fields with regular expressions
Field aliases Alternative names for existing fields
Calculated fields Automatically applied eval expressions

Key Takeaways

  1. eval is the fundamental command for creating new fields
  2. where uses eval functions for powerful filtering
  3. rex extracts fields from unstructured data using regex
  4. Understand the difference between search and where (case sensitivity matters)

Exercises

Exercise 1: Basic

Use eval with case to classify HTTP status codes into "Success" (2xx), "Redirect" (3xx), "Client Error" (4xx), and "Server Error" (5xx).

Exercise 2: Applied

Use rex to extract the process name and PID from syslog messages, then display the event count per process.

Challenge

Combine eval and where to find error events that occurred outside business hours (before 9:00 or after 18:00), and aggregate them by hour of day.


References


Next up: In Day 5, you will learn about statistics and aggregation -- mastering stats, chart, and timechart to summarize your data.