If you’ve inherited a Tableau Server on Linux and nobody set up Tableau Server log rotation, you have a ticking time bomb on your hands. The tabsvc/logs/ directory is not auto-cleaned by default - the only built-in cleanup is the manual tsm maintenance cleanup command, which nobody remembers to run. On a busy server, Tableau Server logs grow at 5-10 GB per day. Three months in, you’re at 99% disk, nativeapi_vizqlserver_*.txt files are 30 GB each, Hyper can’t write extracts, and the dashboard page returns 500.
This post gives you a production-tested Tableau Server log cleanup script for Linux, the cron entry to automate it, and a breakdown of every log directory under tabsvc/logs/ so you know what you’re keeping vs deleting.
TL;DR - Just Give Me the Script
Save as /usr/local/sbin/tableau-log-cleanup.sh and chmod 755:
#!/bin/bash
# Delete Tableau Server rotated logs older than 7 days.
# Active log files (no date suffix) are never matched.
LOGS=/var/opt/tableau/tableau_server/data/tabsvc/logs
DAYS=7
for d in hyper backgrounder contentexploration tabadminagent vizqlserver \
vizdataservice vizportal flowminerva clustercontroller httpd \
appzookeeper tabadmincontroller flowprocessor vizdatanativeservice; do
find "$LOGS/$d" -type f -mtime +$DAYS \
\( -name "*_2[0-9][0-9][0-9]_*" \
-o -name "*.log.2[0-9][0-9][0-9]-*" \
-o -name "*.gz" -o -name "*.zip" \) \
-delete 2>/dev/null
done
Cron - daily at 03:15 UTC:
# Amazon Linux 2023 / RHEL 9 / Ubuntu - install cron if missing
dnf install -y cronie && systemctl enable --now crond
# Then add to root crontab
echo "15 3 * * * /usr/local/sbin/tableau-log-cleanup.sh" | crontab -
That’s the operational answer. The rest of this post explains why it’s safe, what each Tableau log directory does, and how to tune the retention to your environment.
Why Tableau Server Logs Fill the Disk So Fast
Tableau Server ships as a constellation of ~25 services - Hyper, VizQL Server, Backgrounder, Data Server, ActiveMQ, ZooKeeper, Postgres, vizportal - each one writing its own log files into a dedicated subdirectory under:
/var/opt/tableau/tableau_server/data/tabsvc/logs/
A few characteristics make these logs particularly heavy:
- Structured JSON-per-line logs (vizqlserver, hyper) - every operation emits 1-10 lines with full request context. A single dashboard load can write 200+ lines.
- Daily file rotation, no compression - each service writes a new file per day. Old files stay uncompressed (
.txt,.log) until you do something about them. - No automatic retention - Tableau keeps every dated file forever unless you run
tsm maintenance cleanupmanually. - Active health-check chatter - services probe each other every few seconds (cluster controller → Hyper, backgrounder → messaging service). Each probe writes 4-6 log lines. Over 24 hours, that’s ~100,000 lines per service.
On a real production server we resolved recently, vizqlserver alone was generating 1.4 GB per day per instance (with two instances configured). Hyper added another 400-800 MB per day. Multiply by 70 days of accumulated logs and you’ve got ~280 GB just from two services.
If you upgraded from a pre-2022.1 version and your log volume suddenly doubled, that’s not your imagination - Tableau added verbose JMX instrumentation logging across vizqlserver, vizportal, contentexploration, collections, and webhooks. The disable knobs still apply on 2025.3:
tsm configuration set -k vizqlserver.instrumentation.jmx.logging.enabled -v false --force-keys
tsm configuration set -k process.instrumentation.jmx.logging.enabled -v false --force-keys
tsm pending-changes apply
If you’re seeing this pattern, see also our walkthrough of Tableau background extracts failing due to PostgreSQL driver issues - disk pressure and connectivity errors often surface together.
Tableau Server Log Files Explained: What Each Directory Contains
Before deleting anything, it helps to know what you’re cleaning up. The default Tableau Server log file location on Linux is:
/var/opt/tableau/tableau_server/data/tabsvc/logs/
Here’s what every major subdirectory contains and what role it plays.
hyper/ - The Data Engine
Hyper is Tableau’s in-memory analytical database. It’s where extract (.hyper) files live and where every dashboard query that hits an extract actually runs.
What gets logged:
- Every client TCP connection (cluster controller health checks, vizqlserver queries, backgrounder extract refreshes)
- Query plans and execution metrics
- Checkpoint and journal activity
- License checks (
checklicense.log.YYYY-MM-DD)
Typical file pattern: hyper_0_2026_06_03_00_00_00.log (one file per day, started at midnight)
Volume: 300 MB to 1 GB per day on a busy server. Spikes during extract refresh windows.
Why it can balloon: A misconfigured system timezone (we’ve seen Time zone: n/a (UTC, +0000) from timedatectl) makes Hyper emit a timezone-get-local-error line on every single connection. Combined with the every-6-second health probes from cluster controller, that’s 14,400+ error lines per day - which is fixable by running sudo timedatectl set-timezone UTC.
vizqlserver/ - The Rendering Engine
VizQL Server is what turns a workbook into the SVG/HTML you see in the browser. It loads .twb/.twbx files, runs the query plans, and produces the rendered viz.
What gets logged:
nativeapi_vizqlserver_*.txt- JSON trace log of every viz session: workbook load, data source connection, query execution, render output. This is your primary log when debugging “no data” or “unexpected error” issues.vizqlserver_node*.log- Java-side application log (catalina-exec threads, session lifecycle, authorization)tomcat_vizqlserver_access_node*.log- HTTP access log for the embedded Tomcatprotocol/subdirectory - connector-level logs (one file per data source connection class)
Volume: Heaviest of all services on a busy reporting deployment. 500 MB to 2 GB per instance per day. Multiply by the number of vizqlserver instances configured.
When you need these logs: Tracking a session by Session ID: XXXX-1:1 - every dashboard error in the Tableau UI shows you a Session ID, and grep -rl "$SID" . against this directory is the fastest way to find what broke.
backgrounder/ - Extract Refreshes and Subscriptions
The Backgrounder runs all asynchronous jobs: scheduled extract refreshes, subscriptions, flow runs, search indexing, materialized view persistence.
What gets logged:
backgrounder_node*.log- Java app log with one entry per job (jobId=XXX&jobType=RefreshExtracts&siteId=N)nativeapi_backgrounder_*.txt- JSON trace log of extract execution against Hyper
Volume: 500 MB to 3 GB per day depending on extract count and schedule density.
When you need these logs: Investigating failed extract refreshes (finishCode=ERROR), tracking why a subscription didn’t deliver, debugging why a refresh produced a smaller-than-expected .hyper file.
vizportal/ - The Web Application
Vizportal is the Spring Boot application that powers the Tableau Server web UI - project navigation, content listing, permissions, search, scheduling pages.
What gets logged:
vizportal_node*.log- Spring catalina log (request handling, permission checks, repository queries)control_vizportal_*.log- lifecycle log (startup, shutdown, config reload)
Volume: 200 MB to 1 GB per day depending on user activity.
When you need these logs: Login failures, permission errors, search timeouts, OAuth refresh token expirations, Spring bean initialization issues during startup.
dataserver/ and vizdataservice/ - Published Data Source Layer
These services proxy queries from workbooks to published data sources. VizData Service is the newer gRPC-based replacement that handles modern workbook → published data source → Hyper traffic.
What gets logged:
- Connection lifecycle to each published data source
- Query routing decisions
- Authentication exchanges (
connect-using-keychain)
Volume: 200-800 MB per day per instance.
When you need these logs: Workbook says “Could not find Hyper hosts to connect to” - these logs explain why the published data source connection failed.
clustercontroller/ - Service Orchestration
Cluster Controller is the brain that watches every Tableau process, restarts dead ones, distributes work, and writes service state into ZooKeeper.
What gets logged:
clustercontroller.log- current day’s active logclustercontroller.log.YYYY-MM-DD- rotated daily files- Service start/stop events, health check failures, restart attempts
Volume: 200-500 MB per day; spikes massively during partial outages.
When you need these logs: A tsm status shows a service “in an error state” - cluster controller logs explain why.
tabadmincontroller/ and tabadminagent/ - TSM Layer
These are the Tableau Services Manager processes that handle tsm CLI commands, configuration changes, backup/restore jobs, and Service Manager web UI on port 8850.
What gets logged:
- All
tsmoperations (jobs registry, async job execution) - HTTPS request/response to port 8850
- Configuration changes and reconfiguration jobs
Volume: Usually small (50-200 MB/day) - spikes during deployment, restart, or admin work.
When you need these logs: tsm commands return “500 - Server Error”, tsm restart hangs, or you’re investigating why a configuration change didn’t take effect.
activemqserver/ - Internal Messaging
ActiveMQ is the broker Tableau uses for internal pub/sub - subscription delivery, notification fan-out, some coordination between services. The actual broker logs are kept in a separate location, but stdout from the launcher writes here.
What gets logged:
stdout_activemqserver_*.log- JVM startup banner, broker initialization, KahaDB journal recovery messagescontrol_activemqserver_*.log- lifecycle events
Volume: Tiny in normal operation - KBs per day. Spikes during incidents.
When you need these logs: Service shows “in an error state” after a restart - the stdout log will contain the KahaDB corruption messages or BeanFactory errors that explain why ActiveMQ wouldn’t start. Disk-full events frequently corrupt the KahaDB journal, requiring you to move kahadb/ aside before the broker can start again.
httpd/ - Apache Gateway
The Apache HTTP server that fronts every external request before routing to the correct Tableau service.
What gets logged:
access.YYYY_MM_DD_*.log- combined-format HTTP access log (essential for tracing user-reported errors)error.log- Apache error log
Volume: Proportional to user traffic. 100 MB to 1 GB per day on busy public-facing deployments.
When you need these logs: User reports a 500/502/503 - grep the gateway access log for their Session ID to find the exact upstream service that failed.
pgsql/ - Tableau Server Repository
Tableau’s PostgreSQL repository (port 8060) holds workbook metadata, users, schedules, job history.
What gets logged:
- Standard Postgres logs - connection events, slow queries, autovacuum activity, replication state if HA
Volume: 50-300 MB per day.
When you need these logs: Repository corruption suspected, autovacuum issues, repository failover events.
Other Subdirectories Worth Knowing
| Directory | Purpose | Daily volume |
|---|---|---|
flowprocessor/, flowminerva/, floweditor/ | Tableau Prep flow execution | 100-500 MB |
tdsservice/ | Published data source (.tds) metadata service | 50-200 MB |
appzookeeper/ | ZooKeeper coordination service | 20-100 MB |
contentexploration/ | Search indexing and Catalog/Explore features | 100-500 MB |
noninteractive/, interactive/ | Microservice containers (auth, credentials, recommendations) | 50-200 MB each |
webhooks/ | Outbound webhook delivery | 10-50 MB |
crashdumps/ | Process crash dumps - keep recent ones for support tickets | Varies; ZIP archives |
For a deeper view into how Tableau Server architects these services, see our Tableau Server upgrade 2023.3 to 2025.3 walkthrough - many of these directories changed between versions.
How the Cleanup Script Works
The script targets only dated rotated files, never active live files. Here’s the matching logic line by line:
find "$LOGS/$d" -type f -mtime +$DAYS \
\( -name "*_2[0-9][0-9][0-9]_*" \
-o -name "*.log.2[0-9][0-9][0-9]-*" \
-o -name "*.gz" -o -name "*.zip" \) \
-delete 2>/dev/null
| Pattern | Matches files like | Used by |
|---|---|---|
*_2[0-9][0-9][0-9]_* | hyper_0_2026_05_08_00_00_00.log, nativeapi_vizqlserver_1-0_2026_05_03_00_00_00.txt | Hyper, vizqlserver, backgrounder, vizdataservice |
*.log.2[0-9][0-9][0-9]-* | clustercontroller.log.2026-06-02, checklicense.log.2026-05-30 | Cluster controller, license checker, vizportal |
*.gz / *.zip | Any pre-archived rotation | Mixed |
The -mtime +7 filter only deletes files modified more than 7 days ago. The currently-active files - vizqlserver_node1-0.log, clustercontroller.log, checklicense.log (no date suffix) - are never matched, so log writing is never disrupted.
The 2>/dev/null suppresses errors for service directories that don’t exist on your particular topology (you may not have flowminerva/ if Tableau Prep isn’t installed). That’s intentional.
Installing the Cron Job
On Amazon Linux 2023, RHEL 9, and Rocky Linux 9, cron isn’t installed by default. The full install:
# 1. Install cron
dnf install -y cronie
systemctl enable --now crond
# 2. Create the cleanup script
cat > /usr/local/sbin/tableau-log-cleanup.sh <<'EOF'
#!/bin/bash
LOGS=/var/opt/tableau/tableau_server/data/tabsvc/logs
DAYS=7
for d in hyper backgrounder contentexploration tabadminagent vizqlserver \
vizdataservice vizportal flowminerva clustercontroller httpd \
appzookeeper tabadmincontroller flowprocessor vizdatanativeservice; do
find "$LOGS/$d" -type f -mtime +$DAYS \
\( -name "*_2[0-9][0-9][0-9]_*" \
-o -name "*.log.2[0-9][0-9][0-9]-*" \
-o -name "*.gz" -o -name "*.zip" \) \
-delete 2>/dev/null
done
EOF
chmod 755 /usr/local/sbin/tableau-log-cleanup.sh
# 3. Schedule it
echo "15 3 * * * /usr/local/sbin/tableau-log-cleanup.sh" | crontab -
# 4. Verify
crontab -l
systemctl status crond
On Ubuntu/Debian, replace dnf install -y cronie with apt-get install -y cron.
We schedule it at 03:15 UTC specifically because most Tableau extract refresh schedules fire around 02:00-03:00 UTC (or local equivalents). Running cleanup at 03:15 means you’re never deleting logs that backgrounder is actively writing for an in-flight refresh.
Tuning Retention to Your Environment
7 days is a reasonable default that balances disk usage with debug-ability. For tuning:
- High-traffic production with experienced ops team: 3 days. You’ll catch any issue inside the rotation window.
- Standard production: 7 days (the default in our script).
- Regulated environment or compliance-bound: 30+ days. Adjust
DAYS=30and provision the disk to match. - Dev/staging: 2 days, or shorter.
To preview what your current settings would delete without actually deleting:
LOGS=/var/opt/tableau/tableau_server/data/tabsvc/logs
DAYS=7
for d in hyper backgrounder vizqlserver vizportal; do
find "$LOGS/$d" -type f -mtime +$DAYS \
\( -name "*_2[0-9][0-9][0-9]_*" -o -name "*.log.2[0-9][0-9][0-9]-*" \
-o -name "*.gz" -o -name "*.zip" \) -ls 2>/dev/null | head
done
That lists matched files with size and mtime; remove the -ls and add -delete once you’re happy.
When tsm maintenance cleanup Isn’t Enough for Tableau Log Cleanup
Tableau ships a built-in cleanup command:
tsm maintenance cleanup -l --log-files-retention 7 -t -http -r
This is the supported path and you should use it for the parts our script doesn’t touch:
-t- temporary files intabsvc/temp/-http- old rows in thehttp_requeststable in the repository (these never go away on their own and can grow into millions of rows)-r- Redis cache cleanup
But tsm maintenance cleanup -l has a critical limitation: it requires Tableau Services Manager to be healthy and responsive. When your server is at 99% disk, TSM itself frequently can’t run - the admin controller returns 500 errors because dependent services have failed. At that point, the supported path is broken and you need a filesystem-level cleanup like the script above.
Use both:
- The cron script for log files (works even when TSM is down)
- Weekly
tsm maintenance cleanup -t -http -rfor the parts only TSM can touch
To schedule TSM cleanup weekly, add a second cron line (as the tableau user via sudo -u tableau crontab -e). Critically, source the Tableau environment file first - this is the #1 reason tsm cron jobs silently fail:
0 4 * * 0 . /etc/profile.d/tableau_server.sh && tsm maintenance cleanup -t -http -r >/var/log/tsm-cleanup.log 2>&1
What NOT to Delete
A few directories under tabsvc/ look like logs but aren’t safe to delete blindly:
tabsvc/data/tabadmincontroller/keystores/- TSM SSL certificates. Don’t touch.tabsvc/data/pgsql_0.*/- the actual PostgreSQL repository data. Deleting this is data loss.tabsvc/data/dataengine/- Hyper’s working storage for materialized extracts. Deleting this loses extract refresh state.tabsvc/data/filestore/- published workbook and data source storage. Deleting this loses content.tabsvc/files/backups/-.tsbakbackup files. Delete only old ones you’ve verified are no longer needed.tabsvc/activemqserver/*/kahadb/- the ActiveMQ journal. Only delete this if the broker is already broken from corruption (a disk-full event can mid-write a journal file and leave it corrupted -mvit aside, don’trmit).
Stick to tabsvc/logs/ for filesystem cleanup. Anything else, use tsm commands.
Verifying the Script Works
After the first scheduled run, confirm everything is working:
# 1. Check disk recovered
df -h /
# 2. Confirm cleanup ran (mtime on a service's log dir)
ls -lt /var/opt/tableau/tableau_server/data/tabsvc/logs/hyper | head -5
# 3. See cron's execution history
journalctl -u crond --since "8 hours ago" | grep tableau-log-cleanup
If you want logging, change the script’s final done to:
done
BEFORE_KB=$(df -k / | awk 'NR==2 {print $3}')
# ... (the for loop above) ...
AFTER_KB=$(df -k / | awk 'NR==2 {print $3}')
FREED_MB=$(( (BEFORE_KB - AFTER_KB) / 1024 ))
echo "$(date -Is) freed ${FREED_MB} MB" >> /var/log/tableau-log-cleanup.log
Drops a line per day into /var/log/tableau-log-cleanup.log showing how much was reclaimed.
Defence in Depth - Add an OS-Level Disk Alert
Tableau Server has built-in disk alerts via the svcmonitor.notification config - but they depend on SMTP being healthy AND the Messaging Service being up. If a disk-full event also takes down ActiveMQ (which it often does - KahaDB journals corrupt mid-write), the alert never fires. You learn about the outage from a user.
A 10-line OS-level cron is more resilient:
cat > /usr/local/sbin/disk-alert.sh <<'EOF'
#!/bin/bash
USED=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
THRESHOLD=85
if [ "$USED" -gt "$THRESHOLD" ]; then
echo "Tableau / partition at ${USED}% - over ${THRESHOLD}%" \
| mail -s "DISK ALERT $(hostname): ${USED}%" ops@yourcompany.com
fi
EOF
chmod 755 /usr/local/sbin/disk-alert.sh
echo "*/15 * * * * /usr/local/sbin/disk-alert.sh" | crontab -
Runs every 15 min and emails if disk exceeds 85%. For more comprehensive observability across the data platform, our Prometheus and Grafana monitoring services cover application-level metrics that catch issues before disk alerts fire.
Production Checklist
If you’re operationalising Tableau Server for the first time, the full disk hygiene stack we deploy looks like:
- Daily filesystem log cleanup (the script in this post, 7-day retention)
- Weekly
tsm maintenance cleanup -t -http -rfor temp, http_requests, and Redis - System timezone properly set (
timedatectl set-timezone UTCor your business zone) - silences Hyper’stimezone-get-local-errornoise - OS-level disk alert at 85% threshold via cron + email or PagerDuty
- Tableau-level disk alert via
svcmonitor.notificationas a secondary signal - Disk monitoring in Prometheus/Grafana via node_exporter - the authoritative source
- Quarterly review of log retention policy as user count / extract count grows
If you’re running Tableau on AWS specifically, see also our Tableau Server upgrade and AWS region migration walkthrough for the broader hosting checklist.
Recovery: What to Do When You’re Already at 99% Disk
If you found this post because you’re already at 99% disk and dashboards are broken, here’s the emergency sequence:
# 1. Confirm logs are the cause
sudo du -h -d 2 /var/opt/tableau/tableau_server/data/tabsvc/logs 2>/dev/null \
| sort -hr | head -10
# 2. Aggressively delete dated logs (3-day retention for the emergency)
LOGS=/var/opt/tableau/tableau_server/data/tabsvc/logs
for d in hyper backgrounder contentexploration tabadminagent vizqlserver \
vizdataservice vizportal flowminerva clustercontroller httpd; do
find "$LOGS/$d" -type f -mtime +3 \
\( -name "*_2[0-9][0-9][0-9]_*" \
-o -name "*.log.2[0-9][0-9][0-9]-*" \
-o -name "*.gz" -o -name "*.zip" \) \
-delete 2>/dev/null
done
# 3. Check recovered space
df -h /
In our experience this recovers 60-80% of the consumed space within seconds. Once back to a healthy state, install the cron and you’ll never face the same outage twice.
If services come back into “error state” after the disk recovery (specifically the Messaging Service / ActiveMQ), the disk-full event likely corrupted the KahaDB journal. Move the broken journal aside and let Tableau recreate it:
mv /var/opt/tableau/tableau_server/data/tabsvc/activemqserver/0/kahadb \
/var/opt/tableau/tableau_server/data/tabsvc/activemqserver/0/kahadb.broken.$(date +%Y%m%d)
sudo su - tableau -c "tsm restart"
Tableau messaging queues are ephemeral (notifications, subscriptions), so losing the journal is acceptable.
For the full incident-response runbook beyond just disk, see our writeup on building cloud operations runbooks and SLOs - disk-full events are one of the standard scenarios every Tableau runbook should cover.
Frequently Asked Questions
Where are Tableau Server logs stored on Linux?
The default Tableau Server log file location on Linux is /var/opt/tableau/tableau_server/data/tabsvc/logs/. On Windows it’s C:\ProgramData\Tableau\Tableau Server\data\tabsvc\logs\. See the official Tableau log file locations documentation.
Does Tableau Server auto-rotate logs?
No. Tableau Server creates a new log file each day but never deletes the old ones automatically. Cleanup is only triggered by tsm maintenance cleanup -l or a custom script + cron like the one in this post.
How do I reduce Tableau Server log file size?
Three steps: (1) install a daily cron-based cleanup with 7-day retention, (2) disable JMX instrumentation logging via the tsm configuration set commands earlier in this post, (3) keep the system timezone properly set so Hyper stops emitting timezone-get-local-error per connection.
Does this script work on Tableau Server on Windows?
No. Paths and find syntax are Linux-specific. On Windows, use tsm maintenance cleanup plus a PowerShell scheduled task - the til-jmac tableau-server-housekeeping repo has Windows examples.
Will deleting Tableau logs break an open Support ticket?
If you’ve already sent the logs (via tsm maintenance ziplogs), Tableau has the snapshot they need. Going forward, the 7-day retention is enough for almost any new ticket.
Why not use Linux logrotate for Tableau Server logs?
You can, but Tableau’s filenames don’t play well with logrotate patterns (the date is embedded in the middle of some filenames, not as a suffix). A find-based script is simpler, has no config to maintain, and runs in under a second.
Expert Tableau Server Operations Support
A 25-line cron script is the difference between “Tableau quietly serves dashboards for years” and “Tableau hits 99% disk and takes the whole reporting platform down.” Either you have it, or you eventually have an outage.
Our team provides Tableau professional services and data analytics consulting to help you:
- Operationalise Tableau Server on Linux with production-grade log hygiene, automated cleanup, and disk monitoring that catches issues before users do
- Build Tableau-aware observability with Prometheus and Grafana monitoring covering vizqlserver latency, Hyper memory, backgrounder queue depth, and extract refresh SLOs
- Automate Tableau provisioning with Terraform, Ansible, and CI/CD pipelines so log rotation, drivers, timezone, and disk alerts ship with every new server
We specialise in production-grade data platform infrastructure across the UK and Gulf region.