Grafana Alloy: The New Unified Collector (Promtail/Agent Migration)
Migrate from Promtail and Grafana Agent to Alloy. Unified telemetry collection for 2025 and beyond.
Introduction
The observability landscape is evolving rapidly, and Grafana Labs has made a significant strategic shift. In 2024, they announced that Promtail (their dedicated log shipper) is entering maintenance mode, with all future development focused on Grafana Alloy—a unified, vendor-neutral observability collector built on OpenTelemetry standards.
If you’re running Promtail or Grafana Agent today, this guide will help you understand why migration matters, how Alloy differs, and provide a comprehensive deployment strategy for homelabs.
What you’ll learn:
- Why Grafana deprecated Promtail in favor of Alloy
- Understanding Alloy’s architecture and OpenTelemetry integration
- Deploying Alloy with Docker for logs, metrics, and traces
- Migrating from Promtail and Grafana Agent configurations
- Advanced configurations for Docker, Kubernetes, and system logs
- Troubleshooting common issues and performance optimization
Prerequisites:
- Docker and Docker Compose installed
- Existing Loki or Grafana stack (or willingness to deploy)
- Basic understanding of logging and metrics collection
- 512MB+ RAM available for Alloy collector
Why Grafana Alloy? The Promtail Sunset Explained
The Problem with Multiple Collectors
Historically, Grafana’s observability ecosystem required multiple agents:
- Promtail: Log collection for Loki
- Grafana Agent: Metrics, logs, and traces (static mode)
- Grafana Agent Flow: Dynamic configuration with pipelines
- OpenTelemetry Collector: Industry-standard telemetry collection
This fragmentation created confusion, duplicate efforts, and configuration complexity.
Enter Grafana Alloy: One Collector to Rule Them All
Grafana Alloy consolidates all collection capabilities into a single binary:
| Feature | Promtail | Grafana Agent | Alloy |
|---|---|---|---|
| Log Collection | Yes | Yes | Yes |
| Metrics Collection | No | Yes | Yes |
| Trace Collection | No | Yes | Yes |
| OpenTelemetry Native | No | Partial | Yes |
| Dynamic Configuration | No | Flow mode only | Yes |
| Configuration Language | YAML | YAML + River | River |
| Active Development | Maintenance | Maintenance | Active |
| Future Support | Limited | Limited | Full |
Key differentiator: Alloy is built on OpenTelemetry standards, making it vendor-neutral and future-proof.
When Should You Migrate?
Migrate immediately if:
- You need OpenTelemetry support for modern application instrumentation
- You want unified configuration for logs, metrics, and traces
- You’re starting a new observability deployment
Migrate within 6-12 months if:
- You’re running Promtail in production (maintenance mode = security patches only)
- You rely on Grafana Agent static mode (deprecated)
- You want to simplify your agent footprint
You can wait if:
- You’re running Grafana Agent Flow (Alloy is rebranded Flow with enhancements)
- Your Promtail setup works and you don’t need new features
Understanding Alloy Architecture
Core Components
Alloy uses a component-based pipeline architecture:
Sources Processors Exporters
──────── ──────────── ─────────
Files → Filters → Loki
Docker → Transforms → Prometheus
Journald → Enrichment → Tempo
OTel → Sampling → OTLP endpoints Configuration flow example:
1. local.file_match discovers log files
2. loki.source.file tails discovered files
3. loki.process transforms log lines
4. loki.write sends logs to Loki endpoint River Configuration Language
Alloy uses River, a declarative configuration language designed for observability pipelines.
River syntax basics:
// Component syntax: type "label" { config }
loki.source.file "local_logs" {
targets = [
{
__path__ = "/var/log/*.log",
job = "system",
},
]
forward_to = [loki.write.default.receiver]
}
loki.write "default" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
} Key differences from YAML:
- Block-based syntax (similar to HCL/Terraform)
- First-class support for expressions and functions
- Built-in validation and type checking
- Hot-reloading without restarts
Part 1: Basic Deployment with Docker
Quick Start: Alloy + Loki Stack
We’ll deploy a complete logging stack with Alloy and Loki.
Create project directory:
mkdir -p ~/alloy-stack
cd ~/alloy-stack Create docker-compose.yml:
version: '3.8'
services:
# Grafana Loki - Log aggregation database
loki:
image: grafana/loki:latest
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki-data:/loki
networks:
- observability
restart: unless-stopped
# Grafana Alloy - Unified observability collector
alloy:
image: grafana/alloy:latest
container_name: alloy
ports:
- "12345:12345" # UI and API
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
volumes:
- ./alloy-config.river:/etc/alloy/config.river
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
command:
- run
- /etc/alloy/config.river
- --server.http.listen-addr=0.0.0.0:12345
- --storage.path=/var/lib/alloy/data
depends_on:
- loki
networks:
- observability
restart: unless-stopped
environment:
- HOSTNAME=alloy-collector
# Grafana - Visualization and dashboards
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
- ./grafana-datasources.yml:/etc/grafana/provisioning/datasources/datasources.yml
depends_on:
- loki
networks:
- observability
restart: unless-stopped
volumes:
loki-data:
grafana-data:
networks:
observability:
driver: bridge Create alloy-config.river:
// Discover all Docker containers
discovery.docker "containers" {
host = "unix:///var/run/docker.sock"
}
// Tail Docker container logs
loki.source.docker "containers" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.containers.targets
forward_to = [loki.process.add_labels.receiver]
}
// Process and enrich logs
loki.process "add_labels" {
forward_to = [loki.write.loki_endpoint.receiver]
// Add hostname label
stage.static_labels {
values = {
hostname = env("HOSTNAME"),
}
}
// Extract log level from common formats
stage.regex {
expression = "(?i)level=(?P<level>\w+)"
}
stage.labels {
values = {
level = "",
}
}
}
// Send logs to Loki
loki.write "loki_endpoint" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
// Optional: Add authentication
// basic_auth {
// username = "loki"
// password = "secret"
// }
}
}
// System logs from journald (Linux only)
loki.source.journal "system" {
forward_to = [loki.write.loki_endpoint.receiver]
relabel_rules = loki.relabel.journal.rules
labels = {
job = "systemd-journal",
}
}
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
rule {
source_labels = ["__journal__hostname"]
target_label = "hostname"
}
} Create grafana-datasources.yml:
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
url: http://loki:3100
isDefault: true
jsonData:
maxLines: 1000 Start the stack:
docker compose up -d Verify deployment:
# Check all containers are running
docker compose ps
# View Alloy logs
docker logs alloy
# Check Alloy UI
curl http://localhost:12345/ Access services:
- Grafana: http://localhost:3000 (admin/admin)
- Loki: http://localhost:3100/ready
- Alloy UI: http://localhost:12345
Part 2: Migrating from Promtail
Configuration Comparison
Promtail YAML configuration:
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*.log
pipeline_stages:
- regex:
expression: '^(?P<timestamp>S+) (?P<level>S+) (?P<message>.*)$'
- labels:
level: Equivalent Alloy River configuration:
// File discovery with glob patterns
local.file_match "system_logs" {
path_targets = [{
__path__ = "/var/log/*.log",
job = "varlogs",
}]
}
// Tail discovered files
loki.source.file "system" {
targets = local.file_match.system_logs.targets
forward_to = [loki.process.parse_logs.receiver]
}
// Pipeline processing
loki.process "parse_logs" {
forward_to = [loki.write.loki.receiver]
// Extract fields with regex
stage.regex {
expression = "^(?P<timestamp>\S+) (?P<level>\S+) (?P<message>.*)$"
}
// Promote level to label
stage.labels {
values = {
level = "",
}
}
}
// Write to Loki
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
} Automated Migration Tool
Grafana provides a migration tool for converting Promtail configs:
# Install Alloy
docker pull grafana/alloy:latest
# Convert Promtail config
docker run --rm -v $(pwd):/configs grafana/alloy:latest convert --source-format=promtail --output=/configs/alloy-config.river /configs/promtail-config.yml
# Review generated config
cat alloy-config.river Migration checklist:
- Convert configuration using migration tool
- Test Alloy in parallel with Promtail (different labels)
- Verify logs appear in Loki with new labels
- Validate log volumes match (check Loki metrics)
- Monitor Alloy resource usage
- Decommission Promtail after 7-day parallel run
Part 3: Advanced Configurations
Docker Container Logs with Custom Parsing
Collect logs from specific containers with advanced parsing:
// Discover only specific containers
discovery.docker "app_containers" {
host = "unix:///var/run/docker.sock"
filter {
name = "label"
values = ["logging=alloy"]
}
}
// Collect Docker logs
loki.source.docker "apps" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.app_containers.targets
forward_to = [loki.process.docker_logs.receiver]
}
// Advanced log processing pipeline
loki.process "docker_logs" {
forward_to = [loki.write.loki.receiver]
// Drop noisy health check logs
stage.match {
selector = "{container_name="nginx"}"
stage.drop {
expression = ".*GET /health.*"
}
}
// Parse JSON logs
stage.match {
selector = "{container_name="api"}"
stage.json {
expressions = {
level = "level",
message = "msg",
trace_id = "trace_id",
}
}
stage.labels {
values = {
level = "",
}
}
}
// Extract and redact sensitive data
stage.replace {
expression = "password=\S+"
replace = "password=REDACTED"
}
// Add consistent timestamp
stage.timestamp {
source = "timestamp"
format = "RFC3339"
}
} Label containers for collection:
# docker-compose.yml
services:
my-app:
image: my-app:latest
labels:
- "logging=alloy" File-Based Log Collection with Multiline Support
Handle multiline logs (stack traces, JSON formatting):
local.file_match "app_logs" {
path_targets = [{
__path__ = "/var/log/app/*.log",
app = "backend",
}]
}
loki.source.file "applications" {
targets = local.file_match.app_logs.targets
forward_to = [loki.process.multiline.receiver]
}
loki.process "multiline" {
forward_to = [loki.write.loki.receiver]
// Combine Java stack traces into single log entry
stage.multiline {
firstline = "^\d{4}-\d{2}-\d{2}" // Lines starting with date
max_wait_time = "3s"
}
// Parse structured logs
stage.regex {
expression = "^(?P<timestamp>\S+\s+\S+)\s+\[(?P<thread>\S+)\]\s+(?P<level>\w+)\s+(?P<logger>\S+)\s+-\s+(?P<message>[\s\S]+)"
}
// Promote important fields to labels
stage.labels {
values = {
level = "",
thread = "",
}
}
// Parse timestamp
stage.timestamp {
source = "timestamp"
format = "2006-01-02 15:04:05.000"
}
} OpenTelemetry Integration
Receive logs via OpenTelemetry protocol:
// OTLP receiver for logs
otelcol.receiver.otlp "default" {
grpc {
endpoint = "0.0.0.0:4317"
}
http {
endpoint = "0.0.0.0:4318"
}
output {
logs = [otelcol.exporter.loki.default.input]
metrics = [otelcol.exporter.prometheus.default.input]
traces = [otelcol.exporter.otlp.tempo.input]
}
}
// Export OTLP logs to Loki
otelcol.exporter.loki "default" {
forward_to = [loki.write.loki.receiver]
}
// Export metrics to Prometheus
otelcol.exporter.prometheus "default" {
forward_to = [prometheus.remote_write.mimir.receiver]
}
// Export traces to Tempo
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo:4317"
tls {
insecure = true
}
}
}
// Prometheus remote write
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir:9009/api/v1/push"
}
}
// Loki write endpoint
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
} Application instrumentation example (Python):
from opentelemetry import trace, metrics
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Configure OTLP exporter
trace.set_tracer_provider(TracerProvider())
otlp_exporter = OTLPSpanExporter(endpoint="http://alloy:4317", insecure=True)
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(otlp_exporter))
tracer = trace.get_tracer(__name__)
# Use in application
with tracer.start_as_current_span("process_request"):
# Application logic
print("Processing request with automatic trace correlation") Kubernetes DaemonSet Deployment
Deploy Alloy on every Kubernetes node for cluster-wide log collection:
apiVersion: v1
kind: ConfigMap
metadata:
name: alloy-config
namespace: monitoring
data:
config.river: |
// Discover all pods
discovery.kubernetes "pods" {
role = "pod"
}
// Relabel pod metadata
discovery.relabel "pods" {
targets = discovery.kubernetes.pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
}
// Tail pod logs
loki.source.kubernetes "pods" {
targets = discovery.relabel.pods.output
forward_to = [loki.write.loki.receiver]
}
loki.write "loki" {
endpoint {
url = "http://loki.monitoring.svc:3100/loki/api/v1/push"
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alloy
namespace: monitoring
spec:
selector:
matchLabels:
name: alloy
template:
metadata:
labels:
name: alloy
spec:
serviceAccountName: alloy
containers:
- name: alloy
image: grafana/alloy:latest
args:
- run
- /etc/alloy/config.river
- --server.http.listen-addr=0.0.0.0:12345
- --storage.path=/var/lib/alloy/data
ports:
- containerPort: 12345
name: http
volumeMounts:
- name: config
mountPath: /etc/alloy
- name: varlog
mountPath: /var/log
readOnly: true
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: config
configMap:
name: alloy-config
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: alloy
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: alloy
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alloy
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alloy
subjects:
- kind: ServiceAccount
name: alloy
namespace: monitoring Deploy to Kubernetes:
kubectl apply -f alloy-daemonset.yaml
kubectl -n monitoring get pods -l name=alloy
kubectl -n monitoring logs -l name=alloy -f Part 4: Metrics and Traces (Beyond Logs)
Prometheus Metrics Collection
Alloy can replace Prometheus scraping:
// Scrape Prometheus metrics from discovered targets
prometheus.scrape "services" {
targets = [
{"__address__" = "localhost:9090", "job" = "prometheus"},
{"__address__" = "localhost:3000", "job" = "grafana"},
{"__address__" = "cadvisor:8080", "job" = "cadvisor"},
]
forward_to = [prometheus.remote_write.mimir.receiver]
}
// Scrape Kubernetes service monitors
prometheus.operator.servicemonitors "k8s" {
forward_to = [prometheus.remote_write.mimir.receiver]
}
// Remote write to Prometheus/Mimir
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir:9009/api/v1/push"
queue_config {
capacity = 10000
max_shards = 10
max_samples_per_send = 2000
}
}
} Distributed Tracing with Tempo
Collect and forward traces:
// Receive traces via OTLP
otelcol.receiver.otlp "traces" {
grpc {
endpoint = "0.0.0.0:4317"
}
output {
traces = [otelcol.processor.batch.traces.input]
}
}
// Batch processing for efficiency
otelcol.processor.batch "traces" {
output {
traces = [otelcol.exporter.otlp.tempo.input]
}
}
// Send to Tempo
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo:4317"
tls {
insecure = true
}
}
} Full LGTM Stack Configuration
Logs, Grafana, Tempo, Mimir in one Alloy config:
/********************************************
* LOGS - Loki
********************************************/
loki.source.docker "containers" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.all.targets
forward_to = [loki.write.loki.receiver]
}
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}
/********************************************
* METRICS - Prometheus/Mimir
********************************************/
prometheus.scrape "default" {
targets = [
{"__address__" = "localhost:9090", "job" = "prometheus"},
]
forward_to = [prometheus.remote_write.mimir.receiver]
}
prometheus.remote_write "mimir" {
endpoint {
url = "http://mimir:9009/api/v1/push"
}
}
/********************************************
* TRACES - Tempo
********************************************/
otelcol.receiver.otlp "default" {
grpc {
endpoint = "0.0.0.0:4317"
}
output {
traces = [otelcol.exporter.otlp.tempo.input]
}
}
otelcol.exporter.otlp "tempo" {
client {
endpoint = "tempo:4317"
tls {
insecure = true
}
}
}
/********************************************
* DISCOVERY
********************************************/
discovery.docker "all" {
host = "unix:///var/run/docker.sock"
} Part 5: Troubleshooting and Optimization
Common Issues and Solutions
Issue 1: Logs not appearing in Loki
Diagnosis:
# Check Alloy is running
docker logs alloy
# Verify Loki endpoint is reachable from Alloy
docker exec alloy wget -O- http://loki:3100/ready
# Check Alloy UI for component status
curl http://localhost:12345/graph Solutions:
- Verify
loki.writeURL is correct - Check Docker network connectivity
- Review Alloy logs for authentication errors
- Ensure Loki is accepting pushes (check Loki logs)
Issue 2: High memory usage
Symptoms: Alloy container using 1GB+ RAM
Solutions:
// Add memory limits to pipeline
loki.source.file "logs" {
targets = local.file_match.all.targets
forward_to = [loki.write.loki.receiver]
// Limit in-memory buffer
sync_period = "10s"
}
// Batch writes for efficiency
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
// Reduce batch size
batch_size = 512 // Default: 1048576
batch_wait = "1s"
}
} Issue 3: Configuration syntax errors
Diagnosis:
# Validate configuration
docker run --rm -v $(pwd):/configs grafana/alloy:latest fmt /configs/alloy-config.river
# Check for errors
docker logs alloy 2>&1 | grep -i error Solutions:
- Use
alloy fmtto auto-format config - Check component names are unique
- Verify forward_to references exist
- Use Alloy UI to visualize component graph
Performance Optimization
Reduce CPU usage:
// Increase batch intervals
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
batch_wait = "5s" // Wait longer before sending
}
}
// Sample high-volume logs
loki.source.file "noisy_app" {
targets = local.file_match.app.targets
forward_to = [loki.process.sample.receiver]
}
loki.process "sample" {
forward_to = [loki.write.loki.receiver]
// Keep only 10% of logs
stage.sampling {
rate = 0.1
}
} Reduce network traffic:
loki.write "loki" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
// Enable compression
compression = "snappy"
}
} Monitoring Alloy Itself
Alloy exposes metrics about its own performance:
// Scrape Alloy's own metrics
prometheus.scrape "alloy" {
targets = [
{"__address__" = "localhost:12345", "job" = "alloy"},
]
forward_to = [prometheus.remote_write.mimir.receiver]
} Key metrics to monitor:
alloy_component_evaluations_total- Component execution countalloy_loki_write_sent_bytes_total- Data sent to Lokialloy_loki_write_dropped_entries_total- Lost log entries (should be 0)go_memstats_alloc_bytes- Memory usage
Create Grafana dashboard:
- Import dashboard ID: 19419 (Official Alloy Monitoring)
- Select Prometheus data source
- View component health and performance metrics
Part 6: Migration Strategies
Phased Migration Approach
Phase 1: Parallel Deployment (Week 1-2)
// Run Alloy alongside Promtail with different labels
loki.source.docker "alloy_test" {
host = "unix:///var/run/docker.sock"
targets = discovery.docker.all.targets
forward_to = [loki.process.add_source.receiver]
}
loki.process "add_source" {
forward_to = [loki.write.loki.receiver]
stage.static_labels {
values = {
collector = "alloy", // Distinguish from Promtail
}
}
} Validation queries in Grafana:
// Compare log volumes
sum by (collector) (count_over_time({job="containers"}[1h]))
// Verify same containers are logged
count by (container_name, collector) (count_over_time({job="containers"}[1h])) Phase 2: Gradual Cutover (Week 3)
- Increase Alloy confidence: Monitor for 7 days
- Validate log volumes match within 5%
- Check for any missing labels or parsing issues
Phase 3: Decommission Promtail (Week 4)
# Stop Promtail
docker stop promtail
# Monitor for 48 hours
# If no issues, remove completely
docker rm promtail Rollback Plan
If migration fails:
# Quick rollback to Promtail
docker start promtail
# Or redeploy from backup
docker compose -f promtail-compose.yml up -d Keep Promtail config backed up:
cp promtail-config.yml promtail-config.yml.backup
tar czf promtail-backup-$(date +%F).tar.gz promtail-config.yml docker-compose.yml Conclusion
Grafana Alloy represents the future of observability collection in the Grafana ecosystem. While the transition from Promtail requires initial effort, Alloy’s unified approach, OpenTelemetry compatibility, and active development make it a strategic investment.
Key takeaways:
- Alloy consolidates logs, metrics, and traces into one collector
- River configuration language is more powerful than YAML
- OpenTelemetry support future-proofs your observability stack
- Migration tools simplify the transition from Promtail
- Phased migration reduces risk and validates correctness
Your migration timeline:
This week:
- Deploy Alloy in parallel with existing Promtail
- Convert Promtail config using migration tool
- Validate logs appear in Loki
This month: 4. Test advanced features (Docker discovery, multiline, OTLP) 5. Monitor Alloy performance and resource usage 6. Prepare rollback plan
This quarter: 7. Migrate all log collection to Alloy 8. Add metrics and traces collection 9. Decommission Promtail 10. Optimize configuration for your workload
Resources:
- Grafana Alloy Documentation
- River Language Reference
- Migration Guide: Promtail to Alloy
- OpenTelemetry Integration
- Community Forums
The observability landscape is evolving toward OpenTelemetry as the universal standard. By adopting Alloy now, you’re positioning your homelab infrastructure for long-term success with vendor-neutral, standards-based telemetry collection.
Happy collecting!
Guide Version: 1.0 Last Updated: December 2024 Alloy Version: 1.0+ Difficulty Level: Intermediate Estimated Time: 45-90 minutes (deployment + migration)