Loading…
Loading…
Explains the tiered raw log retention pipeline, which archives old logs to object storage, prunes database records, and expires old archives.
The Raw Log Archive Service is an automated, background pipeline responsible for managing the lifecycle of raw API transaction logs and related data. It implements a tiered retention strategy to balance data availability for recent events with the cost-effectiveness of long-term storage.
The service performs three primary functions on independent schedules:
s2r_f5_request_log and s2r_debug_trace tables. Once archived, the large payload columns in the database are nulled to reclaim space.The service is designed to run automatically based on a configured schedule. It can also be triggered manually via an API for operational purposes. Its behavior is primarily controlled by system settings that define retention periods and storage modes.
IMPORTANT
This service operates in a single, default-tenant context. It does not run on a per-tenant basis because retention settings are stored globally. This design prevents a non-default tenant's run from incorrectly applying default retention policies to data it shouldn't access.
The service is composed of three distinct, scheduled jobs that operate independently. Concurrency locks (AtomicBoolean) prevent multiple instances of the same job from running simultaneously. If a scheduled job is triggered while a previous run is still active, the new run is skipped.
The archiving process runs every 15 minutes by default. Its goal is to move log payloads older than a configured database retention period (raw_log_db_retention_days) out of the primary database. The behavior depends on the raw_log_storage_mode system setting.
flowchart TD
subgraph Archiving Process
direction LR
Start(Start Archive Run) --> CheckMode{Storage Mode?}
CheckMode -->|'db_and_gcs'| CheckObjectStore{Object Store Enabled?}
CheckMode -->|'db_only'| DeleteOnlyPath(Delete from DB)
CheckObjectStore -->|Yes| ArchivePath(Archive to Object Store)
CheckObjectStore -->|No| DeleteOnlyPath
subgraph ArchivePath
direction TB
A1[Select due rows from s2r_traffic_log] --> A2[For each row] --> A3{Archive Succeeded?}
A3 -->|Yes| A4[Null DB payloads, set gcs_uri]
A3 -->|No| A5[Increment archive_attempts]
A5 --> A6[End Row]
A4 --> A6
end
subgraph DeleteOnlyPath
direction TB
D1[DELETE from s2r_traffic_log] --> D2[DELETE from s2r_debug_trace]
end
DeleteOnlyPath --> SweepLogs(Sweep Generic & DLQ Logs)
ArchivePath --> SweepLogs
SweepLogs --> End(End Run)
endStorage Modes:
db_and_gcs (Default): This is the tiered storage mode.
s2r_traffic_log and s2r_debug_trace older than raw_log_db_retention_days.f5-request-log/{instance}/{yyyy/MM/dd}/{id}.json.gzdebug-trace/{yyyy/MM/dd}/{correlation_id}/{id}.json.gzgcs_uri column is set to the object key, archived_at is set to the current timestamp, and the large payload columns (request_payload, response_payload, etc.) are set to NULL.archive_attempts counter on the row is incremented. A row will no longer be considered for archiving after 5 failed attempts (MAX_ARCHIVE_ATTEMPTS).db_only: In this mode, logs are not sent to object storage. Rows in s2r_traffic_log and s2r_debug_trace older than raw_log_db_retention_days are deleted directly.
WARNING
If the ObjectStore adapter is not enabled (i.e., no object store bucket is configured), the service will operate in a DELETE-ONLY mode, regardless of the raw_log_storage_mode setting. A warning is logged upon service startup in this state.
s2r_traffic_log Archiving Strategy
To avoid performance issues on large tables, the service uses an intelligent "walking window" strategy to find archivable rows in s2r_traffic_log.
f5ArchiveCursor) marking its position in the table. On startup, the cursor is initialized to 1 day before the most recently archived log, preventing a full table scan of already-processed history.f5ArchiveWindow) starting from the cursor.Generic Log and DLQ Sweeps
As part of the archive run, the service also prunes two other tables:
s2r_generic_request_log: Deletes rows older than generic_raw_log_retention_days (default 60). Deletions are performed in small chunks (500 rows) to avoid long-running transactions.s2r_generic_ingest_dlq: Deletes rows older than a fixed 7 days. This also uses a chunked delete approach.The expiry process runs every 6 hours by default. It is responsible for enforcing the long-term retention policy (raw_log_gcs_retention_days) on the data in object storage.
s2r_traffic_log and s2r_debug_trace that were archived longer ago than the configured retention period.gcs_uri column.
b. After the object is successfully deleted, it deletes the pointer row from the database.The aggregation pruning process runs daily by default. It cleans up historical data from summary tables to keep them performant.
aggregation_retention_days setting (default 365 days).DELETE statements against the following tables for rows older than the retention period:
s2r_observed_traffic_hourlys2r_observed_topologys2r_f5_traffic_hourlys2r_spec_refinement_sample using a fixed 30-day retention period.The service exposes API endpoints that allow for manual triggering of the three main jobs. These are useful for operational tasks or immediate cleanup. A request to trigger a job that is already running will be skipped.
runArchive()Manually triggers a single run of the log archiving and generic log sweeping process.
Example Response:
{
"status": "DONE",
"storageMode": "db_and_gcs",
"usedGcs": true,
"dbRetentionDays": 14,
"f5LogsArchived": 487,
"f5LogsDeleted": 0,
"debugTracesArchived": 12,
"debugTracesDeleted": 0,
"genericRawLogRetentionDays": 60,
"genericRawLogsDeleted": 1530,
"genericIngestDlqRetentionDays": 7,
"genericIngestDlqDeleted": 55,
"time": "2023-10-27T10:00:00.123456Z"
}
runGcsExpiry()Manually triggers a single run of the object store archive expiry process.
Example Response:
{
"status": "DONE",
"gcsRetentionDays": 365,
"f5LogsExpired": 500,
"debugTracesExpired": 23,
"time": "2023-10-27T12:00:00.987654Z"
}
runAggregationPrune()Manually triggers a single run of the aggregation table pruning process.
Example Response:
{
"status": "DONE",
"aggregationRetentionDays": 365,
"deletedObservedTrafficHourly": 1205,
"deletedObservedTopology": 88,
"deletedTrafficHourly": 2400,
"specRefinementSampleRetentionDays": 30,
"deletedSpecRefinementSamples": 500,
"time": "2023-10-28T01:00:00.555555Z"
}
The service's behavior is controlled by a combination of application properties (for scheduling) and dynamic system settings (for retention policies).
These settings are stored in the s2r_system_setting table and can be modified at runtime.
| Name | Type | Default | Description |
|---|---|---|---|
raw_log_storage_mode | String | db_and_gcs | Controls archiving behavior. db_and_gcs archives to object store; db_only deletes from the DB without archiving. |
raw_log_db_retention_days | Integer | 14 | The number of days to keep raw log payloads in the primary database before they are archived or deleted. |
raw_log_gcs_retention_days | Integer | 365 | The number of days to keep logs in the object store after they have been archived. |
generic_raw_log_retention_days | Integer | 60 | The retention period in days for rows in the s2r_generic_request_log table. |
aggregation_retention_days | Integer | 365 | The retention period in days for various hourly and topology aggregation tables. |
These properties configure the scheduler for the service's tasks.
| Name | Type | Default | Description |
|---|---|---|---|
s2r.archive.scheduler.enabled | Boolean | true | A master switch to enable or disable all scheduled tasks in this service. |
s2r.archive.scheduler.initial-delay-ms | String | 60000 | Initial delay in milliseconds before the first run of any scheduled task after the service starts. |
s2r.archive.scheduler.archive-delay-ms | String | 900000 | Fixed delay in milliseconds between the end of one archive run and the start of the next (15 minutes). |
s2r.archive.scheduler.expiry-delay-ms | String | 21600000 | Fixed delay in milliseconds between archive expiry runs (6 hours). |
s2r.archive.scheduler.aggregation-prune-delay-ms | String | 86400000 | Fixed delay in milliseconds between aggregation pruning runs (24 hours). |
The object store bucket name is configured via the ObjectStore adapter, which reads one of the following environment variables.
S2R_RAW_ARCHIVE_BUCKETS2R_OBJECT_STORE_BUCKET| Symptom | Trigger | Meaning & Resolution |
|---|---|---|
Manual trigger returns {"status": "SKIPPED", "reason": "already_running"} | A scheduled or manual run was triggered while a previous run of the same job was still in progress. | This is normal behavior to prevent race conditions. The job will run again at its next scheduled interval. If runs are consistently long and causing skips, investigate the performance of the underlying database queries or object store operations. |
Logs are being deleted instead of archived, despite raw_log_storage_mode being db_and_gcs. | The ObjectStore adapter is not enabled, likely due to a missing bucket configuration (S2R_RAW_ARCHIVE_BUCKET). | The service logs a WARN message at startup: "ObjectStore adapter is not enabled — raw-log archive will run in DELETE-ONLY mode." To fix this, ensure the object store bucket is correctly configured via the appropriate environment variable and restart the service. |
| An archive attempt fails with a log message like "Failed to archive s2r_f5_request_log id=...". | A transient issue with the database or object store, or a problem with the specific log row. | The service automatically increments the archive_attempts counter and will retry on the next scheduled run. If a row fails 5 times, it will be ignored permanently. If all archives are failing, check connectivity to the object store. |
| The log shows "window [...] failed at the minimum size". | A database query for a very small time window in s2r_traffic_log is consistently timing out or failing. | This indicates a severe performance problem in the database when querying the s2r_traffic_log table. The service will stop attempting to archive that table for the current run and try again on the next schedule. Database-level investigation is required. |
| The log shows "DELETE chunk failed" during a generic log sweep. | A DataAccessException occurred while deleting a chunk of rows from s2r_generic_request_log or s2r_generic_ingest_dlq. | The sweep for that specific table is halted for the current run to prevent further errors. The rows deleted so far remain deleted. The sweep will resume from the beginning on the next scheduled archive run. |