Have you ever opened a log file and found email addresses, phone numbers, or exact IPs? If you develop software or manage servers, the answer is yes. The GDPR considers this data personal. Logs, by nature, are stored for long periods — often months or years. The solution is not to stop logging, but to apply anonymization and a retention policy systematically. At Meteora Web, we've managed servers for over 8 years and faced this dilemma dozens of times. We also come from accounting: storing useless logs costs money in space, management, and legal risk. Cleaning data benefits your wallet too.
Why Are Logs a GDPR Problem and Not Just a Technical Issue?
The GDPR imposes principles of data minimization and storage limitation. Raw logs almost always contain personal data: IP addresses (considered personal data by the EU Court of Justice), user agents, requested URLs that may include identifiers, cookies, precise timestamps. If a user exercises the right to erasure (Article 17), their data in logs cannot be ignored. You can't selectively delete a line from a log file without breaking system integrity. The only workable path is anonymization at the source and a clear retention policy.
Sponsored Protocol
Common mistake: thinking logs are just a storage problem. In reality, every non-anonymized log is a potential fine risk. We've seen companies with Apache access logs storing IPs for 5 years. A data subject access request puts them in crisis.
How to Anonymize Logs Without Losing Useful Debug Information?
Anonymization must be irreversible but still retain enough granularity for security and performance analysis. Two main approaches:
Pseudonymization via Hashing
Replace IP with a truncated SHA-256 hash (first 10–16 characters). You keep the ability to recognize the same user (without tracing back identity) and can still count unique IPs. Example in Python:
import re, hashlib
def anonymize_ip(match):
ip = match.group(0)
return hashlib.sha256(ip.encode()).hexdigest()[:16] + ".0.0.0"
log_line = "192.168.1.100 - - [10/Feb/2026:12:00:00 +0000] \"GET /index.html\""
anon = re.sub(r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', anonymize_ip, log_line)
print(anon)
# Output: a1b2c3d4e5f6g7h8.0.0.0 - - [10/Feb/2026:12:00:00 +0000] \"GET /index.html\"On Linux, you can also use sed in the logrotate pipeline:
Sponsored Protocol
sed -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/REDACTED/g' /var/log/nginx/access.log > /tmp/anonymized.log && mv /tmp/anonymized.log /var/log/nginx/access.anonymized.logBut careful: replacing all IPs with "REDACTED" eliminates any analysis capability. If you need to distinguish different IPs, use hashing.
Structured Logs with Separate Fields
Better: produce logs in JSON format that are already free of sensitive data. For example, in Laravel or Node.js, customize the logger to exclude IP or replace it with a hash. Example in Monolog for PHP:
$monolog->pushProcessor(function ($record) {
if (isset($record['extra']['ip'])) {
$record['extra']['ip'] = substr(hash('sha256', $record['extra']['ip']), 0, 16);
}
return $record;
});This approach is cleaner and prevents accidental recording of sensitive data.
What Retention Policy Should You Use for Different Log Types?
Not all logs have the same purpose. GDPR requires storage limited to what is necessary for the processing purpose. Separate logs into three categories:
- Debug/application logs: useful for hours or a few days. Retention max 7 days. Daily rotation.
- Access/security logs: needed for forensics and intrusion detection. Retention recommended 30–90 days. Beyond that, only anonymized.
- Billing/accounting logs: exempt from anonymization but subject to fiscal obligations (10 years). Keep them separate, must not contain IPs or browsing data.
Example logrotate config for nginx with 30-day retention and anonymization before rotation:
Sponsored Protocol
/var/log/nginx/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
sharedscripts
prereotate
/usr/bin/sed -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/HASH/g' $1 > $1.anon
mv $1.anon $1
endscript
postrotate
/usr/sbin/nginx -s reload
endscript
}Note: here we replace with "HASH" — better to use a script that generates a hash per IP. Write an executable that does the hash substitution and call it in prerotate.
Document the Policy
Write a brief internal information: which logs are collected, how long stored, which fields anonymized. This is required by the accountability principle (Art. 5.2). At Meteora Web, we include it in the client's processing register.
Sponsored Protocol
How to Automate Anonymization and Log Rotation in Production?
Automation is crucial to avoid missing steps. Use systemd timers or cron jobs to run periodic anonymization scripts, or integrate anonymization directly into the log collector (rsyslog, syslog-ng, fluentd). Here's an example with rsyslog that replaces IPs on arrival:
# /etc/rsyslog.d/50-anonymize.conf
module(load="omprog")
template(name="AnonIP" type="string" string="%msg:::drop-last-lf%\n")
:msg, contains, "GET" {
action(type="omprog" binary="/usr/local/bin/anon_ip.py" template="AnonIP")
stop
}The /usr/local/bin/anon_ip.py can be the python script above, reading from stdin and writing anonymized logs to stdout. The rsyslog daemon sends each line to the program and then writes the output to the final log file. Disk logs are already anonymized.
Advantage: no need to retroactively anonymize. You do it in real time. Cost: slightly more CPU, but manageable on modern servers.
Periodic Monitoring
Set up an automatic alert if logs contain real IP patterns. A simple grep with cron: grep -E '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' /var/log/nginx/access.log and notify if matches found. Weekly checks ensure anonymization works.
Sponsored Protocol
What to Do Now: Action Checklist
- Map all logs — List log files and services (Apache, Nginx, syslog, custom apps). Where are they? What personal data do they contain?
- Choose anonymization technique — For text logs use sed or Python with truncated SHA256 hashing. For structured logs modify the logger upstream.
- Define differentiated retention — Apply logrotate with daily rotation and retention of 7, 30, or 90 days based on purpose.
- Automate anonymization — Integrate scripts into logrotate pipeline or log collector (rsyslog, fluentd, syslog-ng).
- Document the policy — Write a paragraph for the processing register: log types, purpose, retention, anonymization measure.
- Verify periodically — Set up a script to detect non-anonymized IPs and notify if leaks occur.
You don't need enterprise software or a huge budget. With a few lines of script and logrotate you're compliant. The rest is consistency and periodic checks.
For the full technical compliance picture, read our pillar guide Privacy and GDPR for Developers.