Documentsdify
Log Filtering
Log Filtering
Type
Topic
Status
Published
Created
Jul 9, 2026
Updated
Jul 9, 2026

Log Filtering#

Dify's log filtering system covers two log surfaces — chat/completion app logs (web/app/components/app/log/) and workflow logs (web/app/components/app/workflow-log/) — and shares a common set of time-period primitives. The filtering pipeline spans frontend UI components, client-side state caching, and a backend timezone conversion layer that safely converts user-local date strings to UTC before querying the database.

Key concerns:

  • Time range picker UI: predefined periods and their evolution (simple select → TimeRangePicker component → edition-aware variants)
  • Timezone-aware date queries: how the backend normalizes local times, including DST edge cases
  • Filter state persistence: in-memory session cache and URL query-param strategies
  • Advanced workflow log filters: recent additions for session ID, account email, and custom date ranges

Time Period Mapping & UI Components#

TIME_PERIOD_MAPPING#

Both chat and workflow log filters share TIME_PERIOD_MAPPING, defined in web/app/components/app/log/filter.tsx. It maps period IDs to day-count values:

KeyPeriodValue (days)
1Today0
2Last 7 days7 (default)
3Last 4 weeks28
4Last 3 monthsdayjs.diff(3 months)
5Last 12 monthsdayjs.diff(12 months)
6Month-to-datedayjs.diff(startOf month)
7Quarter-to-datedayjs.diff(startOf quarter)
8Year-to-datedayjs.diff(startOf year)
9All time-1 (omits date params)

Periods 4–8 use dayjs().diff() to compute day counts dynamically, accounting for variable month/quarter lengths. Period 9 is special-cased: when selected, no start/end params are sent to the API .

The default period on load is '2' (last 7 days) .

UI Evolution#

  1. Pre-Nov 2025: Simple dropdown (SimpleSelect) in chart-view.tsx for period selection.
  2. Nov 2025 : Replaced with a dedicated TimeRangePicker component set (index.tsx, range-selector.tsx, date-picker.tsx), enforcing a 30-day window limit and supporting localized date display.
  3. Nov 2025 : Added LongTimeRangePicker for self-hosted (non-SaaS) deployments. Cloud defaults to today; self-hosted defaults to last 7 days and exposes an "all time" option via LONG_TIME_PERIOD_MAPPING.
  4. Jun 2026 : Workflow logs UI extended with a custom dateAfter/dateBefore date range picker in addition to the predefined periods.

Timezone-Aware Backend Queries#

The frontend formats date boundaries as "YYYY-MM-DD HH:mm" strings in local (browser) time and passes them with the user's timezone name. The backend converts them to UTC in parse_time_range() (api/libs/datetime_utils.py) :

  • Uses pytz.timezone(tzname).localize(dt) to attach the correct offset.
  • DST ambiguity (clocks fall back): resolves to non-DST (is_dst=False).
  • Non-existent times (clocks spring forward): advances by 1 hour before localizing.
  • Validates that start ≤ end, raising ValueError otherwise.

PR #32136 added Dayjs utc and timezone plugins on the frontend, ensuring that the start/end strings passed in period-based queries are computed in userProfile.timezone rather than the browser's local offset — fixing query mismatches for users in non-UTC timezones.

Note: All timestamps stored in the database are naive UTC (via naive_utc_now()). The parse_time_range() conversion ensures query boundaries align with stored values.

Filter State Persistence#

Chat/Completion Logs (log/index.tsx)#

Filter state is preserved across navigation using a module-level in-memory cache :

logsStateCache: Map<appId, { queryParams, currPage, limit }>

When the appId changes (navigating to another app), the current state is written to the cache. On mount, the component reads from the cache (falling back to defaultQueryParams) — this means filter selections survive clicks into log detail views and back.

Pagination (page) is also serialized to the URL via URLSearchParams, so a page-1 URL stays clean (the param is omitted when page === 1). PR #29256 introduced this cache to fix a bug where opening a log detail would clear all filter query params.

For the conversation detail drawer, conversation_id is persisted to the URL via the nuqs library , enabling shareable deep-links to specific log entries.

Workflow Logs (workflow-log/index.tsx)#

Workflow logs use React state only — no URL sync or in-memory cache. Default state is { status: 'all', period: '2' }. Filter changes reset currPage to 0. PR #37705 adds session ID, account email, and custom date range filters but keeps the same stateless approach.

workflow_run_id query param support was added in PR #34951 to allow deep-linking into a specific workflow run.

Key Source Files#

FilePurpose
web/app/components/app/log/filter.tsxChat log filter UI; defines TIME_PERIOD_MAPPING
web/app/components/app/log/index.tsxChat log state management, logsStateCache, date range query construction
web/app/components/app/log/list.tsxConversation list; conversation_id URL state via nuqs
web/app/components/app/workflow-log/filter.tsxWorkflow log filter UI; shares TIME_PERIOD_MAPPING
web/app/components/app/workflow-log/index.tsxWorkflow log state management (React state only)
api/libs/datetime_utils.pyparse_time_range(), naive_utc_now(), ensure_naive_utc()
PRDescription
Replaced SimpleSelect with TimeRangePicker component
Added LongTimeRangePicker for self-hosted edition
Fixed filter state cleared when viewing log detail
Timezone-aware frontend date calculations; fixed updated_at mutation on log view
workflow_run_id URL param for workflow logs
Advanced filters (session ID, account email, date range) for workflow logs
Log Filtering | Dosu