Agent skill
time-series-analysis
Analyze event datasets (logs) and intervals over time using OPAL timechart. Use when you need to visualize trends, track metrics over time, or create time-series charts. Covers timechart for temporal binning, bin duration options (1h, 5m, 1d), options(bins:N) for controlling bin count, and understanding temporal output columns (_c_valid_from, _c_valid_to, _c_bucket). Returns multiple rows per group for time-series visualization. For single summaries, see aggregating-event-datasets skill.
Install this agent skill to your Project
npx add-skill https://github.com/rustomax/observe-community-mcp/tree/main/skills/time-series-analysis
SKILL.md
Time-Series Analysis with timechart
The timechart verb bins data over time and applies aggregation functions to create time-series visualizations. This skill teaches you how to analyze trends and patterns in your data over specific time periods using OPAL.
When to Use This Skill
- Visualizing trends over time (error rate by hour, request volume trends)
- Creating time-series charts for dashboards
- Tracking how metrics change throughout the day/week/month
- Comparing behavior across time periods
- Identifying spikes or anomalies in temporal data
Note: timechart returns multiple rows per group (one per time bin) for time-series visualization. For single summary rows, see the aggregating-event-datasets skill.
Prerequisites
- Access to Observe tenant via MCP
- Understanding of event or interval datasets
- Familiarity with aggregation concepts (see aggregating-event-datasets skill)
Key Concepts
timechart - Temporal Binning
timechart groups data into time buckets (bins) and aggregates within each bucket:
- Returns multiple rows per group (one row per time bin)
- Adds temporal columns:
_c_valid_from,_c_valid_to,_c_bucket - Default: 300 bins (Observe picks optimal size)
- Can specify bin duration:
1h,5m,1d,30s, etc. - Can control bin count:
options(bins: N)
Syntax:
timechart [bin_duration], aggregation_function(), group_by(dimension1, dimension2, ...)
timechart vs statsby
| Verb | Output | Use Case |
|---|---|---|
statsby |
1 row per group (total across time range) | Summary reports, totals |
timechart |
Multiple rows per group (time-series) | Trending, charts, dashboards |
Example comparison:
statsby (summary):
statsby count(), group_by(namespace)
# Output: 1 row per namespace
timechart (time-series):
timechart 1h, count(), group_by(namespace)
# Output: 24 rows per namespace (for 24h query)
Temporal Output Columns
timechart adds three columns to output:
_c_valid_from- Start of time bin (nanosecond timestamp)_c_valid_to- End of time bin (nanosecond timestamp)_c_bucket- Bucket identifier (integer)
Discovery Workflow
Same as other event/interval skills:
Step 1: Find dataset
discover_context("kubernetes logs")
Step 2: Get schema
discover_context(dataset_id="YOUR_DATASET_ID")
Note fields for filtering, grouping, and aggregating.
Basic Patterns
Pattern 1: Fixed Bin Duration
Use case: Hourly error count over 24 hours
filter contains(body, "error")
| timechart 1h, count()
Explanation: Bins data into 1-hour buckets, counts errors in each bucket. For 24h time range, returns 24 rows.
Output:
_c_valid_from,_c_valid_to,count,_c_bucket
1763110800000000000,1763114400000000000,4,489753
1763107200000000000,1763110800000000000,5,489752
...
Pattern 2: Time-Series by Dimension
Use case: Error count per hour, grouped by namespace
filter contains(body, "error")
| make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart 1h, count(), group_by(namespace)
Explanation: Returns multiple rows per namespace - one row for each hour. Suitable for multi-line chart showing errors over time per namespace.
Output:
_c_valid_from,_c_valid_to,namespace,count,_c_bucket
1763110800000000000,1763114400000000000,kube-system,4,489753
1763107200000000000,1763110800000000000,kube-system,5,489752
1763100000000000000,1763103600000000000,observe,16,489750
1763100000000000000,1763103600000000000,kube-system,5,489750
...
Pattern 3: Controlling Bin Count
Use case: Get exactly 10 data points across time range
filter contains(body, "error")
| make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart options(bins: 10), count(), group_by(namespace)
Explanation: Observe automatically calculates bin duration to produce at most 10 bins across the query time range.
Pattern 4: Multiple Aggregations
Use case: Track multiple metrics over time
make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart 1h,
total_logs:count(),
group_by(namespace)
Explanation: Calculate multiple aggregations per time bin. Each metric becomes a column in the output.
Pattern 5: Default Auto-Binning
Use case: Let Observe pick optimal bin size
filter contains(body, "error")
| make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart count(), group_by(namespace)
Explanation: Without specifying duration or bins, Observe defaults to 300 bins with optimal size for the time range.
Complete Example
End-to-end workflow for creating an error rate dashboard.
Scenario: Create a time-series chart showing error trends per namespace over the last 24 hours.
Step 1: Discovery
discover_context("kubernetes logs")
Found: Dataset "Kubernetes Explorer/Kubernetes Logs" (ID: 42161740)
Step 2: Build query
filter contains(body, "error") or contains(body, "ERROR")
| make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart 1h, error_count:count(), group_by(namespace)
Step 3: Execute
execute_opal_query(
query="[query above]",
primary_dataset_id="42161740",
time_range="24h"
)
Step 4: Interpret results
_c_valid_from,_c_valid_to,namespace,error_count,_c_bucket
1763110800000000000,1763114400000000000,kube-system,4,489753
1763107200000000000,1763110800000000000,kube-system,5,489752
1763103600000000000,1763107200000000000,kube-system,5,489751
1763100000000000000,1763103600000000000,observe,16,489750
1763100000000000000,1763103600000000000,kube-system,5,489750
...
Analysis:
- Each row represents one hour for one namespace
kube-systemhas relatively stable error rate (4-7 per hour)observenamespace shows a spike (16 errors in one hour)- Data suitable for line chart with multiple series (one per namespace)
Visualization:
- X-axis: Time (
_c_valid_fromor_c_valid_to) - Y-axis:
error_count - Series/Lines: One per
namespace
Advanced Patterns
Pattern 6: Bin Duration Options
Common bin durations:
# Fine-grained (short time ranges)
timechart 30s, count() # 30 second bins
timechart 1m, count() # 1 minute bins
timechart 5m, count() # 5 minute bins
# Medium (hours to days)
timechart 1h, count() # 1 hour bins
timechart 6h, count() # 6 hour bins
# Coarse (days to weeks)
timechart 1d, count() # 1 day bins
timechart 1w, count() # 1 week bins
Choosing bin size:
- Match your query time range: 1h range → 1m or 5m bins, 7d range → 1h or 6h bins
- Consider visualization: Too many bins = cluttered chart, too few = lost detail
- Start with auto-binning, adjust as needed
Pattern 7: Rate Calculations
Use case: Calculate error rate (errors per second)
filter contains(body, "error")
| make_col namespace:string(resource_attributes."k8s.namespace.name")
| timechart 1h, error_count:count(), group_by(namespace)
| make_col error_rate:float64(error_count)/3600.0 # errors per second (1h = 3600s)
Explanation: Adds derived column calculating rate per second from hourly counts.
Common Pitfalls
Pitfall 1: Using statsby When You Want Time-Series
❌ Wrong (if you want trends):
statsby count(), group_by(namespace)
# Returns 1 row per namespace (no time dimension)
✅ Correct:
timechart 1h, count(), group_by(namespace)
# Returns multiple rows per namespace (time-series)
Why: statsby gives totals, timechart gives trends over time.
Pitfall 2: Too Many Bins
❌ Wrong:
timechart 1s, count() # For 24h range = 86,400 bins!
✅ Correct:
timechart 1m, count() # For 24h range = 1,440 bins (manageable)
# OR
timechart options(bins: 100), count() # Let Observe pick duration
Why: Too many bins overwhelm visualization and query performance.
Pitfall 3: Confusing Timestamps
❌ Wrong:
# Trying to use timestamp field directly for binning
filter timestamp > 1763100000000000000
| statsby count(), group_by(timestamp)
✅ Correct:
# Use timechart for temporal binning
timechart 1h, count()
Why: timechart automatically handles time binning - don't need manual timestamp grouping.
Pitfall 4: Expecting Single Summary
❌ Wrong (if you want total):
timechart 1h, count()
# Returns 24 rows for 24h range - need to sum them manually!
✅ Correct (for total):
statsby count()
# Returns 1 row with total
Why: timechart is for time-series, not totals. Use statsby for summaries.
Tips and Best Practices
- Start with defaults: Use
timechart count()first, adjust bin size after seeing results - Match bin to time range: Short ranges (1h) → small bins (1m), long ranges (30d) → large bins (1d)
- Name your metrics: Use
error_count:count()not justcount() - Filter first: Apply filters before
timechartfor better performance - Visualization-ready: Output is designed for time-series charts
- Test with small ranges: Start with 1h or 24h, expand once query works
- options(bins: N): Use when you want specific number of data points
Bin Duration Reference
Time Units:
s- secondsm- minutesh- hoursd- daysw- weeks
Examples:
30s- 30 seconds5m- 5 minutes1h- 1 hour6h- 6 hours1d- 1 day1w- 1 week
Default Behavior:
- No duration specified:
options(bins: 300)- Observe picks optimal size options(bins: 1)- Single bin (equivalent to statsby)options(bins: N)- At most N bins across time range
Additional Resources
For more details, see:
- RESEARCH.md - Tested patterns including timechart vs statsby comparison
- OPAL Documentation - Official OPAL docs
Related Skills
- [aggregating-event-datasets] - For single summary rows (statsby)
- [filtering-event-datasets] - For filtering before time-series aggregation
- [analyzing-interval-datasets] - timechart works on Intervals too (spans, resources)
Last Updated: November 14, 2025 Version: 1.0 Tested With: Observe OPAL v2.x
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
working-with-reference-tables
Work with Reference Tables (static CSV lookup data) using OPAL to enrich datasets with descriptive information. Use when you need to map IDs to human-readable names, add static metadata from CSV uploads, or perform lookups without temporal considerations. Covers both explicit and implicit lookup patterns, column name matching, and when to choose Reference Tables vs Resources vs Correlation Tags.
working-with-resources
Work with Resource datasets (mutable state tracking) using OPAL temporal joins. Use when you need to enrich Events/Intervals with contextual state information, track resource state changes over time, or navigate between datasets using temporal relationships. Covers temporal join mechanics (lookup, join, follow), automatic field matching, and when to use Resources vs Reference Tables.
analyzing-text-patterns
Extract and analyze recurring patterns from log messages, span names, and event names using punctuation-based template discovery. Use when you need to understand log diversity, identify common message structures, detect unusual formats, or prepare for log parser development. Works by removing variable content and preserving structural markers.
detecting-anomalies
Detect anomalies in metrics and time-series data using OPAL statistical methods. Use when you need to identify unusual patterns, spikes, drops, or outliers in observability data. Covers statistical outlier detection (Z-score, IQR), threshold-based alerts, rate-of-change detection with window functions, and moving average baselines. Choose pattern based on data distribution and anomaly type.
aggregating-gauge-metrics
Aggregate pre-computed metrics (gauge, counter, delta types) using OPAL. Use when analyzing request counts, error rates, resource utilization, or any numeric metrics over time. Covers align + m() + aggregate pattern, summary vs time-series output, and common aggregation functions. For percentile metrics (tdigest), see analyzing-tdigest-metrics skill.
aggregating-event-datasets
Aggregate and summarize event datasets (logs) using OPAL statsby. Use when you need to count, sum, or calculate statistics across log events. Covers make_col for derived columns, statsby for aggregation, group_by for grouping, aggregation functions (count, sum, avg, percentile), and topk for top N results. Returns single summary row per group across entire time range. For time-series trends, see time-series-analysis skill.
Didn't find tool you were looking for?