# Events

Quickly explore and visualize your logs to debug issues and discover patterns using **Log SQL**.

#### Want a dashboard with multiple charts and alerts?

Use [Dashboards](https://betterstack.com/docs/logs/dashboards/) instead of **Events** to get:

- **Dashboards**: Put multiple charts on a dashboard to get an overview of your apps and services.
- **Faster charts**: Dashboards use **Logs to metrics** to load weeks of your logs in seconds.
- **Alerts**: Set up anomaly alerts for errors and latencies of your apps and CPU and memory of your servers.

## Getting started

Start exploring your logs in [Events](https://telemetry.betterstack.com/team/0/explore-logs) → **Create query**. Select a source. 
Use the following **Log SQL**:

```sql
[label Log SQL query counting number of log lines by level]
SELECT {{time}} as time,
  count(*) as value,
  JSONExtract(raw, 'level', 'Nullable(String)') AS series
FROM {{source}}
WHERE time BETWEEN {{start_time}} AND {{end_time}}
GROUP BY time, series
```

**Log SQL** queries use [ClickHouse SQL](https://clickhouse.com/docs/en/sql-reference), which is largely similar to ANSI SQL you’re likely familiar with.

In the query above, we use `count(*)` to get the number of logs for each `level`.

### Extracting log fields

In **Explore**, you can access any field in your logs. Extract top-level or nested fields using `JSONExtract()` function:

- **Top-level field** `level`: `JSONExtract(raw, 'level', 'Nullable(String)')`  
- **Nested field** `context.request.status`: `JSONExtract(raw, 'context', 'request', 'status', 'Nullable(String)')`

#### Case-insensitive field access

If the case of fields in your logs can vary (for example, `level` and `Level`), you can use `JSONExtractCaseInsensitive`, in the same way as `JSONExtract`.

`JSONExtractCaseInsensitive(raw, 'level', 'Nullable(String)')` would fetch either `level` or `Level` from a log, depending on which is present.

### Query variables

On top of SQL, Log SQL queries feature variables like `{{source}}` or `{{time}}`. Variables conveniently insert selected source, current time range, and other selected values into your queries. Read more about [query variables](https://betterstack.com/docs/logs/dashboards/variables/).

## Video overview

<div style="position: relative; padding-bottom: 56.25%; height: 0;"><iframe src="https://www.loom.com/embed/d77fbcd75176437ea8e35bf20e20f46e?sid=d14932d4-077c-4698-a2ca-062a24e998b2" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>

## Explore with examples

### Chart number of logs by host

Chart how many logs your servers produce:

```sql
[label Log SQL query counting number of log lines by host]
SELECT {{time}} as time,
  count(*) as value,
  JSONExtract(raw, 'context', 'hostname', 'Nullable(String)') AS series
FROM {{source}}
WHERE time BETWEEN {{start_time}} AND {{end_time}}
GROUP BY time, series
```

#### Want to use the extracted field in dashboards?

[Add a metric](https://betterstack.com/docs/logs/dashboards/logs-to-metrics/) in Logs to metrics for your source:

- **Metric**: Name your metric `hostname`.
- **JSON dot notation**: Write JSON path `context.hostname`.
- **Type**: Select **String**.
- **Aggregations**: Leave **No aggregation** selected.

Once added, you can use `hostname` column on [Dashboards](https://betterstack.com/docs/logs/dashboards/).

### Visualize geographical data

Extend your log analysis by visualizing geographical data. If your logs contain IP addresses or GPS coordinates, you can use our [built-in GeoIP features to plot events on a map](https://betterstack.com/docs/logs/visualizing-geographical-data/), helping you identify regional trends or issues.

### Track specific error in your logs

Match specific errors in logs `message` field using `CASE` and `LIKE`. The `LIKE` operator performs a case-sensitive search:

```sql
[label Log SQL query to match a specific error]
SELECT {{time}} AS time, 
  COUNT(CASE WHEN 
    JSONExtractString(raw, 'message')
    LIKE '%connection lost%' 
    THEN TRUE ELSE FALSE
  END) AS value
FROM {{source}}
WHERE time BETWEEN {{start_time}} AND {{end_time}}
GROUP BY time
```

#### Want to create an alert for the matched error?

[Add a metric](https://betterstack.com/docs/logs/dashboards/logs-to-metrics/) in Logs to metrics for your source:

- **Metric**: Name your metric `is_connection_lost_error`.
- **SQL expression**: Use the `CASE` statement - i.e. everything starting with `CASE` and ending with `END` including the `CASE` and `END` keywords.
- **Type**: Select **Boolean**.
- **Aggregations**: Leave **No aggregation** selected.

To create the alert:

- Go to [Dashboards](https://telemetry.betterstack.com/team/0/dashboards) → **Create dashboard**.  
- Create a chart with `is_connection_lost_error = 1` filter.
- Add an alert in the right sidebar. 

![Screenshot of creating an error tracking metric](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/5ea54a5c-3612-4981-d97d-2cdbcca2a500/lg2x =2138x1742)
