All Products
Search
Document Center

Simple Log Service:Common examples of log data analysis

Last Updated:Jun 10, 2026

Ready-to-use SQL queries for common log analysis scenarios — alerting, traffic monitoring, latency analysis, and Tomcat web service observability.

Trigger an alert when the error rate exceeds 40% in the past 5 minutes

To alert on a spike in HTTP 500 errors, calculate the error rate per topic over 5-minute windows using max_by to find the window with the highest error count, then filter topics where that window accounts for more than 40% of total errors. The HAVING clause applies both conditions: error rate above 40% and a minimum of 500 total errors to exclude false positives on low-traffic topics.

status:500 | select __topic__, max_by(error_count,window_time)/1.0/sum(error_count) as error_ratio, sum(error_count) as total_error  from (
select __topic__, count(*) as error_count , __time__ - __time__ % 300  as window_time  from log group by __topic__, window_time
) 
group by __topic__  having  max_by(error_count,window_time)/1.0/sum(error_count)   > 0.4  and sum(error_count) > 500 order by total_error desc limit 100

Collect traffic statistics and configure alerts

To monitor inbound traffic per minute and alert when it drops below a threshold, aggregate traffic by minute and normalize it to a per-minute rate. The divisor greatest(max(__time__) - min(__time__),1) handles sub-minute windows at query boundaries — greatest ensures the denominator is at least 1, preventing division by zero when all events fall within the same second.

* | SELECT SUM(inflow) / greatest(max(__time__) - min(__time__),1) as inflow_per_minute, date_trunc('minute',__time__)  as minute group by minute

Calculate the average latency by data size

To understand how data size affects latency, bucket requests into five size ranges using CASE WHEN and calculate the average latency in each bucket. This reveals whether large payloads are the source of latency spikes.

* | select avg(latency) as latency , case when originSize < 5000 then 's1' when originSize < 20000 then 's2' when originSize < 500000 then 's3' when originSize < 100000000 then 's4' else 's5' end as os group by os

Return the percentages of different results

To see each department's share of the total count, use a subquery to calculate per-department counts and a window function to get the grand total. The expression sum(c) over() computes the sum across all rows without collapsing them, so you can divide each row's count by the total in a single pass.

* |  select   department, c*1.0/ sum(c) over ()  from(select  count(1) as c, department   from log group by department)

Count the number of URLs that meet the query condition

To count login and registration requests per minute without complex branching, use COUNT_IF with a LIKE pattern for each URL type. COUNT_IF is more concise than the equivalent CASE WHEN expression and easier to extend when you need to track additional URL patterns.

* | select  count_if(uri like '%login') as login_num, count_if(uri like '%register') as register_num, date_format(date_trunc('minute', __time__), '%m-%d %H:%i') as time  group by time order by time limit 100

General aggregate analysis

Query the global distribution of clients by PV

To see which countries your clients come from and how much traffic each generates, use the ip_to_country function to resolve client IP addresses to countries, then group by country and count page views (PVs). Display the results on a world map — see Configure a world map.

* |
select
  ip_to_country(client_ip) as ip_country,
  count(*) as pv
group by
  ip_country
order by
  pv desc
limit
  500

Query the category and PV trend of request methods

To track how different HTTP request methods trend over time, truncate timestamps to the minute using date_format(date_trunc('minute', ...)), then group by both time and request_method to get per-method PV counts. Display the results on a line chart with the x-axis set to t, the y-axis set to pv, and the aggregate column set to request_method. For more information, see Line chart.

* |
select
  date_format(date_trunc('minute', __time__), '%m-%d %H:%i') as t,
  request_method,
  count(*) as pv
group by
  t,
  request_method
order by
  t asc
limit
  10000

Query the distribution of requests by user agent and PV

To break down traffic by user agent — including request volume, traffic size, and status code distribution — group by http_user_agent and compute: total PVs, request and response traffic in MB (rounded to two decimal places), and the percentage of responses in each status code range (2xx, 3xx, 4xx, 5xx) using CASE WHEN expressions. Display the results in a table. For more information, see Basic table.

* |
select
  http_user_agent as "User agent",
  count(*) as pv,
  round(sum(request_length) / 1024.0 / 1024, 2) as "Request traffic (MB)",
  round(sum(body_bytes_sent) / 1024.0 / 1024, 2) as "Response traffic (MB)",
  round(
    sum(
      case
        when status >= 200
        and status < 300 then 1
        else 0
      end
    ) * 100.0 / count(1),
    6
  ) as "Percentage of status code 2xx (%)",
  round(
    sum(
      case
        when status >= 300
        and status < 400 then 1
        else 0
      end
    ) * 100.0 / count(1),
    6
  ) as "Percentage of status code 3xx (%)",
  round(
    sum(
      case
        when status >= 400
        and status < 500 then 1
        else 0
      end
    ) * 100.0 / count(1),
    6
  ) as "Percentage of status code 4xx (%)",
  round(
    sum(
      case
        when status >= 500
        and status < 600 then 1
        else 0
      end
    ) * 100.0 / count(1),
    6
  ) as "Percentage of status code 5xx (%)"
group by
  "User agent"
order by
  pv desc
limit
  100

Query the daily consumption and trend forecast for the current month

To visualize actual daily spending alongside a forecast for the rest of the month, deduplicate billing records by RecordID, aggregate daily totals, and pass the result to sls_inner_ts_regression. This function takes the timestamp, the daily total, a label array, the forecast interval in seconds (86400 for daily), and the number of forecast points (60), then returns both actual and predicted values. Where res.real is NaN, the row is a forecast point — the CASE WHEN expression surfaces forecast values only for future dates. Display on a line chart with the x-axis set to time and two y-axes for actual and forecast consumption. For more information, see Line chart.

source :bill |
select
  date_format(res.stamp, '%Y-%m-%d') as time,
  res.real as "Actual consumption",case
    when is_nan(res.real) then res.pred
    else null
  end as "Forecast consumption",
  res.instances
from(
    select
      sls_inner_ts_regression(
        cast(day as bigint),
        total,
        array ['total'],
        86400,
        60
      ) as res
    from
      (
        select
          *
        from
          (
            select
              *,
              max(day) over() as lastday
            from
              (
                select
                  to_unixtime(date_trunc('day', __time__)) as day,
                  sum(PretaxAmount) as total
                from
                  (
                    select
                      RecordID,
                      arbitrary(__time__) as __time__,
                      arbitrary(ProductCode) as ProductCode,
                      arbitrary(item) as item,
                      arbitrary(PretaxAmount) as PretaxAmount
                    from
                      log
                    group by
                      RecordID
                  )
                group by
                  day
                order by
                  day
              )
          )
        where
          day < lastday
      )
  )
limit
  1000

Query the consumption percentage of each service for the current month

To see which services account for the largest share of your bill, aggregate spending by ProductName, rank services by total expense using the row_number window function, then collapse services ranked 7th and below (or with zero or negative charges) into an "Other" category. Display the results on a donut chart. For more information, see Configure a donut chart.

source :bill |
select
  case
    when rnk > 6
    or pretaxamount <= 0 then 'Other'
    else ProductName
  end as ProductName,
  sum(PretaxAmount) as PretaxAmount
from(
    select
      *,
      row_number() over(
        order by
          pretaxamount desc
      ) as rnk
    from(
        select
          ProductName,
          sum(PretaxAmount) as PretaxAmount
        from
          log
        group by
          ProductName
      )
  )
group by
  ProductName
order by
  PretaxAmount desc
limit
  1000

Compare yesterday's expense against the same day last month

To compare yesterday's spending against the same day last month, use the compare function with a 604800-second (7-day) offset. COALESCE ensures that days with no charges return 0 rather than NULL. The output array diff contains three values: diff[1] is yesterday's expense, diff[2] is the same day last month, and diff[3] is the ratio. Use round to round the inner expense value to three decimal places, then format the outer diff values to two decimal places, and multiply diff[3] by 100 minus 100 to express the ratio as a percentage change. Display on a trend chart — see Trend chart.

source :bill |
select
  round(diff [1], 2),
  round(diff [2], 2),
  round(diff [3] * 100 -100, 2)
from(
    select
      compare("Expense of the previous day", 604800) as diff
    from(
        select
          round(coalesce(sum(PretaxAmount), 0), 3) as "Expense of the previous day"
        from
          log
      )
  )

Tomcat web service analysis

Query the trend of Tomcat request status

To see how Tomcat request status codes change over time, use date_trunc to truncate timestamps to the minute and date_format to format the time as hours and minutes, then group by both time and status to count requests per status code per minute. Display on a flow chart with the x-axis set to time, the y-axis set to count, and the aggregate column set to status. For more information, see Flow chart.

* |
select
  date_format(date_trunc('minute', __time__), '%H:%i') as time,
  COUNT(1) as c,
  status
GROUP by
  time,
  status
ORDER by
  time
LIMIT
  1000

Query the distribution of PVs and UVs for Tomcat access over time

To track both page views (PVs) and unique visitors (UVs) on the same timeline, use time_series to group events into 2-minute buckets and approx_distinct to count unique remote_addr values. approx_distinct uses HyperLogLog for efficient approximate deduplication — accurate enough for monitoring without the cost of exact deduplication. Display on a multi-axis line chart with the x-axis set to time and two y-axes for uv and pv. For more information, see Add a line chart with multiple y-axes.

* |
select
  time_series(__time__, '2m', '%H:%i', '0') as time,
  COUNT(1) as pv,
  approx_distinct(remote_addr) as uv
GROUP by
  time
ORDER by
  time
LIMIT
  1000

Query the number of Tomcat error requests and compare with the previous hour

To compare the current error count against one hour ago, use the compare function with a 3600-second offset. The function returns an array: c1 is the current error count, c2 is the count from 3,600 seconds ago, and c3 is the percentage change (c1/c2 * 100 - 100). Display on a donut chart using c1 as the display value and c3 as the comparison value. For more information, see Configure a donut chart.

status >= 400 |
SELECT
  diff [1] AS c1,
  diff [2] AS c2,
  round(diff [1] * 100.0 / diff [2] - 100.0, 2) AS c3
FROM
  (
    select
      compare(c, 3600) AS diff
    from
      (
        select
          count(1) as c
        from
          log
      )
  )

Query the top 10 URIs in Tomcat requests

To find the most-requested URIs, group by request_uri, count PVs per URI, and return the top 10 in descending order. Display on a bar gauge with the x-axis set to page and the y-axis set to pv. For more information, see Configure a basic bar gauge.

* |
SELECT
  request_uri as page,
  COUNT(*) as pv
GROUP by
  page
ORDER by
  pv DESC
LIMIT
  10

Query the types and distribution of Tomcat clients

To understand what clients are hitting your Tomcat server, group by user_agent and count requests per type. Display on a donut chart with the type set to user_agent and the value column set to c. For more information, see Configure a donut chart.

* |
SELECT
  user_agent,
  COUNT(*) AS c
GROUP BY
  user_agent
ORDER BY
  c DESC

Collect statistics on the outbound Tomcat traffic

To monitor outbound Tomcat traffic over time, use time_series to bucket events into 10-second intervals and sum body_bytes_sent per bucket. Display on a line chart with the x-axis set to time and the y-axis set to body-sent. For more information, see Configure the x-axis and the y-axis of a line chart.

* |
select
  time_series(__time__, '10s', '%H:%i:%S', '0') as time,
  sum(body_bytes_sent) as body_sent
GROUP by
  time
ORDER by
  time
LIMIT
  1000

Query the percentage of error Tomcat requests

To see what fraction of all requests are errors, compute the error count and total count in a subquery using CASE WHEN status >= 400, then divide and round to two decimal places in the outer query. Display on a dial. For more information, see Configure a dial.

* |
select
  round((errorCount * 100.0 / totalCount), 2) as errorRatio
from
  (
    select
      sum(
        case
          when status >= 400 then 1
          else 0
        end
      ) as errorCount,
      count(1) as totalCount
    from
      log
  )