A high-performance, production-ready Rust application that collects audit logs from Microsoft Office365 and delivers them to your SIEM or log management system in real-time.
Built with Rust | Production-Ready | Zero Duplicates | Multi-Tenant | Standalone Service
Download the latest release for your platform from the Releases page:
- Linux x86_64:
office_audit_log_collector-linux-x86_64 - Linux ARM64:
office_audit_log_collector-linux-arm64 - macOS:
office_audit_log_collector-darwin - Windows:
office_audit_log_collector-windows.exe
# 1. Download binary
wget https://github.com/therajvira/office365-log-collector/releases/latest/download/office_audit_log_collector-linux-x86_64
chmod +x office_audit_log_collector-linux-x86_64
sudo mv office_audit_log_collector-linux-x86_64 /usr/local/bin/office_audit_log_collector
# 2. Create directories
sudo mkdir -p /etc/office365-collector
sudo mkdir -p /var/lib/office365-collector
sudo mkdir -p /var/log/office365
# 3. Create config file (see Configuration section below)
sudo nano /etc/office365-collector/config.yaml
# 4. Create systemd service
sudo tee /etc/systemd/system/office365-collector.service << 'EOF'
[Unit]
Description=Office365 Audit Log Collector
After=network.target
[Service]
Type=simple
User=ubuntu
Group=ubuntu
WorkingDirectory=/var/lib/office365-collector
ExecStart=/usr/local/bin/office_audit_log_collector --config /etc/office365-collector/config.yaml
Restart=always
RestartSec=10
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/office365-collector /var/log/office365
[Install]
WantedBy=multi-user.target
EOF
# 5. Enable and start
sudo systemctl daemon-reload
sudo systemctl enable office365-collector
sudo systemctl start office365-collector
# 6. Check status
sudo systemctl status office365-collector
sudo journalctl -u office365-collector -fCreate /etc/office365-collector/config.yaml:
# Office365 Audit Log Collector Configuration
enabled: true
# Run continuously every 5 minutes
interval: "5m"
# Only collect new events (recommended for production)
only_future_events: true
# State files location
workingDir: "/var/lib/office365-collector"
# Office365 Credentials (from Azure AD App Registration)
tenants:
- tenant_id: "YOUR-TENANT-ID"
client_id: "YOUR-CLIENT-ID"
client_secret: "YOUR-CLIENT-SECRET"
api_type: "commercial" # commercial, gcc, or gcc-high
# Subscribe to audit feeds
subscriptions:
- "Audit.AzureActiveDirectory"
- "Audit.Exchange"
- "Audit.SharePoint"
- "Audit.General"
- "DLP.All"
# Output: Write to JSON files (simplest option)
output:
file:
path: "/var/log/office365/audit.json"
separateByContentType: true
# Logging
log:
path: "" # Empty = stdout (for journalctl)
debug: falseWith separateByContentType: true, logs are written to separate files:
/var/log/office365/
├── AuditAzureActiveDirectory.json # User logins, admin changes
├── AuditExchange.json # Email operations
├── AuditSharePoint.json # File operations
├── AuditGeneral.json # Teams, PowerBI, etc.
└── DLPAll.json # Data Loss Prevention events
Each file is in JSONL format (one JSON object per line), compatible with:
- Filebeat → Elasticsearch
- Vector → Kafka/Clickhouse/etc.
- Promtail → Loki
- Logstash
- Any log shipper that reads JSON
| Output | Use Case | Configuration |
|---|---|---|
| File (Default) | Standalone service, read by log shipper | output.file |
| Graylog | Direct GELF output to Graylog | output.graylog |
| Fluentd | Stream to Fluentd/Vector via forward protocol | output.fluentd |
| Azure Log Analytics | Send to Azure Sentinel/OMS | output.azureLogAnalytics |
output:
file:
path: "/var/log/office365/audit.json"
separateByContentType: trueoutput:
fluentd:
tenantName: "MyCompany"
address: "fluentd-host"
port: 24224output:
graylog:
address: "graylog-host"
port: 12201output:
azureLogAnalytics:
workspaceId: "YOUR-WORKSPACE-ID"
# Also requires --oms-key command line argument- Microsoft 365 Compliance → Audit → Turn on auditing
- Wait 1-2 hours for audit pipeline to activate
- Azure Portal → Azure AD → App registrations → New registration
- Name:
Office365-Log-Collector - Account type: Single tenant
- Save Tenant ID and Client ID
- Certificates & secrets → New client secret
- Save the Secret Value (shown only once!)
- API permissions → Add permission → Office 365 Management APIs
- Application permissions:
ActivityFeed.ReadActivityFeed.ReadDlp
- Click Grant admin consent
Collect from multiple Office365 tenants:
tenants:
- tenant_id: "tenant1-id"
client_id: "app1-client-id"
client_secret: "app1-secret"
api_type: "commercial"
- tenant_id: "tenant2-id"
client_id: "app2-client-id"
client_secret: "app2-secret"
api_type: "gcc" # Government cloudConfigure logrotate for file output:
sudo tee /etc/logrotate.d/office365 << 'EOF'
/var/log/office365/*.json {
daily
rotate 7
compress
delaycompress
notifempty
missingok
create 0644 ubuntu ubuntu
}
EOFsudo systemctl status office365-collector
sudo journalctl -u office365-collector -f# Watch file sizes grow
watch -n 10 'ls -lh /var/log/office365/*.json'
# Count logs
wc -l /var/log/office365/*.json
# View recent logs
tail -5 /var/log/office365/AuditAzureActiveDirectory.json | jq .[INFO] Starting Office365 collector in daemon mode with interval: 300s
[INFO] Loaded 21428 known blobs into LRU cache
[INFO] Done! Blobs found: 9 | Blobs successful: 9 | Logs saved: 2063
[INFO] Sleeping for 300 seconds until next collection...
docker run -d \
--name office365-collector \
--restart unless-stopped \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
-v office365-state:/var/lib/office365-collector \
-v office365-logs:/var/log/office365 \
ghcr.io/therajvira/office365-log-collector:latest# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone and build
git clone https://github.com/therajvira/office365-log-collector.git
cd office365-log-collector
cargo build --release
# Binary at: ./target/release/office_audit_log_collector- Check audit logging is enabled in Office365
- Verify API permissions (ActivityFeed.Read, ActivityFeed.ReadDlp)
- Ensure admin consent was granted
- Check credentials in config.yaml
- Verify tenant_id, client_id, client_secret
- Regenerate client secret if expired
- Check API permissions
Reduce settings in config:
collect:
cacheSize: 100000 # Default: 500000
maxThreads: 25 # Default: 50- Multi-Tenant Support - Collect from multiple Office365 tenants
- 5 Subscription Types - DLP, Exchange, SharePoint, Azure AD, General
- Daemon Mode - Runs continuously (configurable interval)
- Zero Duplicates - LRU cache with TTL-based blob tracking
- Multiple Outputs - File, Fluentd, Graylog, Azure Log Analytics
- Government Cloud - Commercial, GCC, GCC-High support
- Memory Efficient - Bounded caches, chunked processing
- Automatic Retry - Handles API failures gracefully
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.