Skip to content
This is an archived version of the documentation downloaded from LogScale Documentation Archives. Up to date documentation, and documentation for later versions, is available on LogScale Documentation

## `selectLast()`

Specify a set of fields to select from events; for each field it will keep the field value of the most recent event with that field. This can be used to collect field values across a range of events, where each event contributes one or more fields to the output event. It is usually most useful in combination with `groupBy()`.

Parameter | Type | Required | Default Value | Description
--- | --- | --- | --- | ---
`fields`[a] | array of strings | required |  | The names of the fields to keep.
[a] The parameter name `fields` can be omitted.

Hide omitted argument names for this function

Show omitted argument names for this function

> Omitted Argument Names

> The argument name for `fields` can be omitted; the following forms of this function are equivalent:

> logscale Syntax

>     selectLast(["value"])

> and:

> logscale Syntax

>     selectLast(fields=["value"])

> These examples show basic structure only.

### `selectLast()` Syntax Examples

Given event data like {id:a, from:x}, {id:a, to:x}, — a table with {id, from, to} tuples.

logscale

    groupBy(id, function=selectLast([from,to]))

There is no function for a logical opposite (select the first matching event for a given field) of the `selectLast()` function, but for an arbitrary array of values as in the previous example, the equivalent to `selectLast([from,to])` query would be:

logscale

    [
     { from = *
    | head(1)
    | select(from) },
     { to = *
    | head(1)
    | select(to) }
    ]

When working with the @timestamp field, the query:

    selectLast([@timestamp])

Is equivalent to using `max()`:

    max(@timestamp)

The opposite operation can be achieved by using `min()`:

    min(@timestamp)

### `selectLast()` Examples

Click + next to an example below to get the full details.

#### Analyze User Logon Patterns And Activity

Summarize user authentication events across the environment using the `groupBy()` function

##### Query

logscale

    #event_simpleName=UserLogon
    | groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])
    | table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)

##### Introduction

In this example, the `groupBy()` function is used to analyze user logon events by aggregating authentication data across multiple systems, providing visibility into who is logging in, from where, and how often.

Example incoming data might look like this:

@timestamp | #event_simpleName | UserName | name | aid | aip | ComputerName | event_platform | LocalIP | LogonDomain | LogonServer | LogonType
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
2025-11-05T10:15:00Z | UserLogon | john.doe | John Doe | aid123 | 10.1.1.100 | DESKTOP-001 | Windows | 192.168.1.10 | CORP | DC01 | 2
2025-11-05T10:16:00Z | UserLogon | john.doe | John Doe | aid123 | 10.1.1.100 | DESKTOP-001 | Windows | 192.168.1.10 | CORP | DC01 | 2
2025-11-05T10:20:00Z | UserLogon | jane.smith | Jane Smith | aid124 | 10.1.1.101 | LAPTOP-002 | Windows | 192.168.1.11 | CORP | DC01 | 10
2025-11-05T10:25:00Z | UserLogon | admin.user | Admin User | aid125 | 10.1.1.102 | SERVER-001 | Windows | 192.168.1.12 | CORP | DC01 | 3
2025-11-05T10:30:00Z | UserLogon | jane.smith | Jane Smith | aid124 | 10.1.1.101 | LAPTOP-002 | Windows | 192.168.1.11 | CORP | DC01 | 10

##### Step-by-Step

1. Starting with the source repository events.

2. logscale

       #event_simpleName=UserLogon

   Filters events to include only user logon events where #event_simpleName equals `UserLogon`.

3. logscale

       | groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])

   Groups logon events by multiple fields including user, system, and network information. For each group, it calculates two aggregate values:

   - The total count of logon events using `count(@timestamp)`.

   - The most recent logon timestamp using `selectLast([@timestamp])`.

     Note that `selectLast([@timestamp])` is equivalent to using `max(@timestamp)`.

4. logscale

       | table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)

   Creates a table displaying key logon information, including timestamp, user details, system information, and logon type. The `limit` parameter is set to return up to `20,000` results.

5. Event Result set.

##### Summary and Results

The query is used to analyze user authentication patterns by aggregating logon events and providing a comprehensive view of user access across the environment.

This query is useful, for example, to identify unusual logon patterns, monitor privileged account usage, and track user access across different systems.

Sample output from the incoming example data:

@timestamp | UserName | ComputerName | aid | aip | event_platform | LocalIP | LogonDomain | LogonType | _count
--- | --- | --- | --- | --- | --- | --- | --- | --- | ---
2025-11-05T10:16:00Z | john.doe | DESKTOP-001 | aid123 | 10.1.1.100 | Windows | 192.168.1.10 | CORP | 2 | 2
2025-11-05T10:30:00Z | jane.smith | LAPTOP-002 | aid124 | 10.1.1.101 | Windows | 192.168.1.11 | CORP | 10 | 2
2025-11-05T10:25:00Z | admin.user | SERVER-001 | aid125 | 10.1.1.102 | Windows | 192.168.1.12 | CORP | 3 | 1

Note that the _count field shows the number of logon events for each unique combination of grouped fields. The @timestamp shown is the most recent logon time for each group.

Different LogonType values indicate various authentication methods (for example, 2 for interactive, 3 for network, 10 for remote interactive).

The opposite query showing user logoff events might look like this:

logscale

    #event_simpleName=UserLogoff
    | groupBy([UserName, name, aid, aip, ComputerName, event_platform, LocalIP, LogonDomain, LogonServer, LogonType], function=[count(@timestamp), selectLast([@timestamp])])
    | table([@timestamp, UserName, ComputerName, aid, aip, event_platform, LocalIP, LogonDomain, LogonType], limit=20000)

#### List All EC2 Hosts With FirstSeen Data Within 14 Days

List all the EC2 hosts with FirstSeen data within 14 days using the `groupBy()` function with `selectLast()`

##### Query

logscale

    #repo=sensor_metadata #data_source_name=aidmaster cloud.provider = "AWS_EC2_V2"
    | groupBy([aid], function=(selectLast([event_platform, aid, ComputerName, AgentVersion, FirstSeen])), limit=max)
    | FirstSeen := formatTime("%FT%T%z", field=FirstSeen)
    | TimeDelta := now() - duration("14d")

##### Introduction

In this example, the `groupBy()` function is used with `selectLast()` to retrieve the latest information about `AWS EC2` instances running CrowdStrike sensors, showing their platform, hostname, agent version, and when they were first seen, with a 14-day reference point for age comparison.

Example incoming data (raw data in sensor_metadata) might look like this:

@timestamp | aid | cloud.provider | event_platform | ComputerName | AgentVersion | FirstSeen
--- | --- | --- | --- | --- | --- | ---
2025-05-20T10:00:00Z | 1234abcd | AWS_EC2_V2 | Windows | ec2-web-01 | 6.45.15678 | 2025-01-15T08:30:00Z
2025-05-21T11:00:00Z | 1234abcd | AWS_EC2_V2 | Windows | ec2-web-01 | 6.45.15679 | 2025-01-15T08:30:00Z
2025-05-22T12:00:00Z | 5678efgh | AWS_EC2_V2 | Linux | ec2-app-02 | 6.45.15678 | 2025-02-01T14:45:00Z
2025-05-23T13:00:00Z | 5678efgh | AWS_EC2_V2 | Linux | ec2-app-02 | 6.45.15679 | 2025-02-01T14:45:00Z
2025-05-24T14:00:00Z | 90123ijk | AWS_EC2_V2 | Windows | ec2-db-03 | 6.45.15678 | 2025-03-10T09:15:00Z
2025-05-25T15:00:00Z | 90123ijk | AWS_EC2_V2 | Windows | ec2-db-03 | 6.45.15679 | 2025-03-10T09:15:00Z

##### Step-by-Step

1. Starting with the source repository events.

2. logscale

       #repo=sensor_metadata #data_source_name=aidmaster cloud.provider = "AWS_EC2_V2"

   Searches in the sensor_metadata repository, and filters for #data_source_name fields containing the value `aidmaster`, looking for cloud.provider of the type `AWS_EC2_V2` only.

3. logscale

       | groupBy([aid], function=(selectLast([event_platform, aid, ComputerName, AgentVersion, FirstSeen])), limit=max)

   Groups results by the field aid (Agent ID). Then, for each unique group, selects the most recent values for the fields: event_platform, aid, ComputerName, AgentVersion, FirstSeen.

   Using the `selectLast()` within the `groupBy()` is what actually selects the most recent record for each group.

4. logscale

       | FirstSeen := formatTime("%FT%T%z", field=FirstSeen)

   Formats the timestamp in the FirstSeen field into ISO 8601 format. The result is stored back in the FirstSeen field.

5. logscale

       | TimeDelta := now() - duration("14d")

   Calculates timestamp from 14 days ago, and returns the results into a new field named TimeDelta. The calculation is done by subtracting a 14-day duration from the current time using `duration()`.

   This new TimeDelta field that represents a timestamp from 14 days ago, can be used for filtering or comparing against the FirstSeen timestamps.

6. Event Result set.

##### Summary and Results

The query is used to retrieve the latest information about AWS EC2 instances running CrowdStrike sensors, showing their platform, hostname, agent version, and when they were first seen, with a 14-day reference point for age comparison.

The query is useful, for example, for auditing EC2 instance coverage, identifying newly added EC2 instances within the last two weeks, monitoring sensor versions or identifying aging or outdated installations.

Sample output from the incoming example data:

aid | event_platform | ComputerName | AgentVersion | FirstSeen | TimeDelta
--- | --- | --- | --- | --- | ---
1234abcd | Windows | ec2-web-01 | 6.45.15679 | 2025-01-15T08:30:00+0000 | 2025-05-12T13:06:56+0000
5678efgh | Linux | ec2-app-02 | 6.45.15679 | 2025-02-01T14:45:00+0000 | 2025-05-12T13:06:56+0000
90123ijk | Windows | ec2-db-03 | 6.45.15679 | 2025-03-10T09:15:00+0000 | 2025-05-12T13:06:56+0000

Each aid appears only once with its most recent values. Note that TimeDelta value is based on the current date provided (Mon, 26 May 2025 13:06:56 GMT).

#### Monitor Data Sources for Stale Data

Identify log sources that have stopped sending data using the `selectLast()` function

##### Query

logscale

    selectLast([@ingesttimestamp]) | lasteventseentime := @ingesttimestamp
    currenttime := now()
    timediff := (currenttime - lasteventseentime)
    timeinmins := timediff/60000 | timeinmins := format(format="%d", field=timeinmins)
    timeinhours := timediff/3600000 | timeinhours := format(format="%d", field=timeinhours)
    timeindays := timediff/86400000 | timeindays := format(format="%d", field=timeindays)
    case {
            timeinmins > 30 | timeinmins < 61 | format("No new data in the last %s minutes", field=["timeinminutes"], as=Alert.Name) ;
            timeinmins > 60 | timeinhours < 24 | format("No new data in the last %s hours", field=["timeinhours"], as=Alert.Name) ;
            timeinhours > 24 | format("No new data in the last %s days", field=["timeindays"], as=Alert.Name)
            }

##### Introduction

In this example, the `selectLast()` function is used to identify when data sources have stopped sending events by comparing the timestamp of the most recent event with the current time. The query calculates the elapsed time and formats an appropriate message based on whether the delay is in minutes, hours, or days.

A time window of 30 days is recommended to effectively identify stale data sources and calculate the appropriate time elapsed since the last event.

Example incoming data might look like this:

@timestamp | @ingesttimestamp | source | message
--- | --- | --- | ---
2025-11-05T10:00:00.000Z | 2025-11-05T10:00:01.000Z | webserver-01 | User login successful
2025-11-05T10:01:00.000Z | 2025-11-05T10:01:01.000Z | webserver-01 | Connection established
2025-11-05T10:02:00.000Z | 2025-11-05T10:02:01.000Z | webserver-01 | Session timeout
2025-11-05T10:03:00.000Z | 2025-11-05T10:03:01.000Z | webserver-02 | User login successful
2025-10-15T09:00:00.000Z | 2025-10-15T09:00:01.000Z | webserver-03 | Last event received

##### Step-by-Step

1. Starting with the source repository events.

2. logscale

       selectLast([@ingesttimestamp]) | lasteventseentime := @ingesttimestamp

   Identifies the most recent @ingesttimestamp value within the 30-day window and returns the result in a new field named lasteventseentime. The `selectLast()` function will find the most recent event even if it is from several days ago, making it essential for identifying stale data sources.

3. logscale

       currenttime := now()

   Gets the current time and returns the result in a field named currenttime. This timestamp will be used as the reference point for calculating elapsed time.

4. logscale

       timediff := (currenttime - lasteventseentime)

   Calculates the time difference between current time and last event time in milliseconds, returning the result in timediff.

5. logscale

       timeinmins := timediff/60000 | timeinmins := format(format="%d", field=timeinmins)

   Converts the time difference to minutes and formats it as an integer. The division by 60000 converts milliseconds to minutes.

6. logscale

       timeinhours := timediff/3600000 | timeinhours := format(format="%d", field=timeinhours)

   Converts the time difference to hours and formats it as an integer. The division by 3600000 converts milliseconds to hours.

7. logscale

       timeindays := timediff/86400000 | timeindays := format(format="%d", field=timeindays)

   Converts the time difference to days and formats it as an integer. The division by 86400000 converts milliseconds to days.

8. logscale

       case {
               timeinmins > 30 | timeinmins < 61 | format("No new data in the last %s minutes", field=["timeinminutes"], as=Alert.Name) ;
               timeinmins > 60 | timeinhours < 24 | format("No new data in the last %s hours", field=["timeinhours"], as=Alert.Name) ;
               timeinhours > 24 | format("No new data in the last %s days", field=["timeindays"], as=Alert.Name)
               }

   Uses case statement to create appropriate alert messages based on the time elapsed since the last event:

   - For 30-60 minutes: Creates an alert message showing the delay in minutes.

   - For 1-24 hours: Creates an alert message showing the delay in hours.

   - For more than 24 hours: Creates an alert message showing the delay in days.

   The formatted message is returned in the Alert.Name field.

9. Event Result set.

##### Summary and Results

The query is used to monitor data freshness by calculating the time elapsed since the last event was received, providing appropriately formatted alerts based on the duration of inactivity.

This query is useful, for example, to create alerts for stale data sources, monitor data pipeline health, ensure continuous data ingestion, and identify potential issues with data collection or transmission.

Sample output from the incoming example data:

@timestamp | @ingesttimestamp | source | Alert.Name
--- | --- | --- | ---
2025-11-05T10:03:00.000Z | 2025-11-05T10:03:01.000Z | webserver-02 | No new data in the last 45 minutes
2025-10-15T09:00:00.000Z | 2025-10-15T09:00:01.000Z | webserver-03 | No new data in the last 21 days

Note that it is recommended to set the time window for this search to 30 days to ensure proper detection of stale data sources. This extended window allows the query to find and report on data sources that have not sent data for extended periods, up to 30 days in the past.

#### Enter search term