Guide · AWS Transfer Family · Monitoring

AWS Transfer Family CloudWatch Monitoring — Metrics, CloudTrail Events, and EventBridge Notifications

AWS Transfer Family emits CloudWatch metrics for file counts and byte volumes, structured logs to CloudWatch Logs for each session and transfer event, CloudTrail records for every API call, and EventBridge events for transfer completions and failures — giving you four independent observability layers for SFTP infrastructure backing MCP tools. For MCP server developers, the most actionable monitoring pattern is: CloudWatch alarms on FilesIn and BytesIn to detect when partner file drops stop (zero uploads after expected delivery window), EventBridge rules to trigger downstream MCP processing on each completed upload, and CloudWatch Logs Insights queries to investigate authentication failures or slow transfers. The critical observability gotcha: Transfer Family CloudWatch metrics are only emitted if you attach a Logging Role to the server at creation time — a server without a logging role generates no CloudWatch metrics or structured logs, and the gap is invisible until you look for metrics and find nothing.

TL;DR

Attach a logging role with logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents to your Transfer Family server. CloudWatch metrics appear in the AWS/Transfer namespace with dimensions ServerId and Username. Key metrics: FilesIn / FilesOut (count of files transferred in/out), BytesIn / BytesOut (data volume). EventBridge receives File Transfer Complete and File Transfer Failed events automatically — no server configuration needed. Set a CloudWatch alarm on FilesIn with a "missing data = breaching" policy to page when expected partner uploads don't arrive within their SLA window.

Enabling CloudWatch logging

Transfer Family logs are opt-in — you must specify a logging role ARN when creating or updating the server. Without a logging role, the server operates but emits no metrics, no structured session logs, and no authentication event logs. The logging role is assumed by the Transfer Family service (not by individual users) and needs only CloudWatch Logs write permissions.

# IAM role trust policy for Transfer Family logging
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "transfer.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

# IAM role permission policy for CloudWatch Logs
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:DescribeLogStreams",
      "logs:PutLogEvents"
    ],
    "Resource": "arn:aws:logs:*:*:log-group:/aws/transfer/*"
  }]
}

# Create the logging role
LOGGING_ROLE_ARN=$(aws iam create-role \
  --role-name TransferFamilyLoggingRole \
  --assume-role-policy-document file://trust-policy.json \
  --query 'Role.Arn' --output text)

aws iam put-role-policy \
  --role-name TransferFamilyLoggingRole \
  --policy-name CloudWatchLogsPolicy \
  --policy-document file://logs-policy.json

# Attach logging role to existing server
aws transfer update-server \
  --server-id s-0abc \
  --logging-role $LOGGING_ROLE_ARN

# Verify logging role is set
aws transfer describe-server \
  --server-id s-0abc \
  --query 'Server.LoggingRole'

Transfer Family logs appear in CloudWatch Logs under the log group /aws/transfer/<server-id>. Each SFTP session creates a separate log stream named after the session ID. Log entries include authentication events, file operations (OPEN, CLOSE, READ, WRITE), and session termination. The log format is structured JSON — suitable for Logs Insights queries and metric filters.

CloudWatch metrics

Transfer Family emits four metrics in the AWS/Transfer namespace. Metrics are available with a 1-minute granularity and are retained for 15 months. All four metrics support filtering by ServerId (aggregate across all users on a server) and Username (per-user granularity). Per-user metrics are the most useful for MCP monitoring — you can alert when a specific partner's upload volume deviates from their expected pattern.

# List available Transfer Family metrics
aws cloudwatch list-metrics \
  --namespace AWS/Transfer \
  --dimensions Name=ServerId,Value=s-0abc

# Get FilesIn metric for a specific user over the last 24 hours
aws cloudwatch get-metric-statistics \
  --namespace AWS/Transfer \
  --metric-name FilesIn \
  --dimensions \
    Name=ServerId,Value=s-0abc \
    Name=Username,Value=alice \
  --start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
  --period 3600 \
  --statistics Sum

# Get BytesIn across all users for the last 7 days
aws cloudwatch get-metric-statistics \
  --namespace AWS/Transfer \
  --metric-name BytesIn \
  --dimensions Name=ServerId,Value=s-0abc \
  --start-time $(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
  --period 86400 \
  --statistics Sum

# Available metrics:
# FilesIn    — count of files uploaded by SFTP clients
# FilesOut   — count of files downloaded by SFTP clients
# BytesIn    — total bytes uploaded
# BytesOut   — total bytes downloaded

A common gotcha: Transfer Family does not emit a metric for zero transfers in a period — if no files were uploaded in an hour, there is no FilesIn datapoint for that hour. CloudWatch treats missing datapoints as "no data" by default. To alert on zero uploads within an expected window, create an alarm with TreatMissingData: breaching and a threshold of >= 1 file in the evaluation period. If no datapoint exists (no uploads), the alarm treats missing as a breach and fires.

CloudWatch alarms for partner SLA monitoring

SFTP file-intake pipelines typically have delivery SLAs — partners commit to uploading files by a certain time each day. A CloudWatch alarm with missing data = breaching is the standard pattern for detecting when an expected file hasn't arrived. Configure the alarm to fire if FilesIn for a specific partner (username dimension) is zero during the SLA window — typically a 1-hour evaluation period spanning the expected delivery time.

# Alarm: alert if alice uploads zero files between 08:00-09:00 UTC
# (set up the alarm in advance; adjust evaluation period to cover the SLA window)
aws cloudwatch put-metric-alarm \
  --alarm-name transfer-alice-daily-upload-missing \
  --alarm-description "Alice daily file upload missing — SLA breach" \
  --namespace AWS/Transfer \
  --metric-name FilesIn \
  --dimensions \
    Name=ServerId,Value=s-0abc \
    Name=Username,Value=alice \
  --statistic Sum \
  --period 3600 \
  --evaluation-periods 1 \
  --threshold 1 \
  --comparison-operator LessThanThreshold \
  --treat-missing-data breaching \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:sftp-alerts \
  --ok-actions arn:aws:sns:us-east-1:123456789012:sftp-alerts

# Alarm: alert on abnormally high byte volume (possible data exfiltration)
aws cloudwatch put-metric-alarm \
  --alarm-name transfer-alice-high-bytesout \
  --alarm-description "Unusually high download volume for alice" \
  --namespace AWS/Transfer \
  --metric-name BytesOut \
  --dimensions \
    Name=ServerId,Value=s-0abc \
    Name=Username,Value=alice \
  --statistic Sum \
  --period 3600 \
  --evaluation-periods 1 \
  --threshold 104857600 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:sftp-security-alerts

The TreatMissingData: breaching vs notBreaching distinction is critical: use breaching when absence of data is itself a problem (expected upload didn't arrive), and notBreaching when absence of data is normal (no unusual download activity today is fine). Never use the default missing behavior for SLA monitoring — it holds the alarm in its previous state, which can mask a missed upload if the alarm was previously OK.

EventBridge for real-time file processing

Transfer Family emits three event types to EventBridge: File Transfer Complete, File Transfer Failed, and Session Terminated. These events are published automatically to the default event bus — no server configuration required beyond having a functioning Transfer Family server. EventBridge rules filter these events and route them to Lambda functions, SQS queues, or Step Functions state machines for downstream MCP processing.

# EventBridge rule — trigger Lambda on every completed upload
aws events put-rule \
  --name transfer-file-complete \
  --event-pattern '{
    "source": ["aws.transfer"],
    "detail-type": ["File Transfer Complete"],
    "detail": {
      "ServerId": ["s-0abc"],
      "StatusCode": ["200"]
    }
  }'

# Add Lambda as target (Lambda must grant EventBridge invoke permission)
aws events put-targets \
  --rule transfer-file-complete \
  --targets '[{
    "Id": "mcp-processor",
    "Arn": "arn:aws:lambda:us-east-1:123456789012:function:mcp-process-upload"
  }]'

# EventBridge rule — alert on failed transfers
aws events put-rule \
  --name transfer-file-failed \
  --event-pattern '{
    "source": ["aws.transfer"],
    "detail-type": ["File Transfer Failed"],
    "detail": {
      "ServerId": ["s-0abc"]
    }
  }'

# File Transfer Complete event structure:
# {
#   "source": "aws.transfer",
#   "detail-type": "File Transfer Complete",
#   "detail": {
#     "ServerId": "s-0abc",
#     "Username": "alice",
#     "SessionId": "sftp-sess-uuid",
#     "FileLocation": {
#       "S3Bucket": "mcp-file-intake",
#       "S3Key": "alice/reports/q1.csv",
#       "S3VersionId": "v123"
#     },
#     "BytesTransferred": 45678,
#     "TransferStatus": "OK",
#     "RequestBytes": 45678,
#     "StatusCode": "200"
#   }
# }

The FileLocation object in the event contains the S3 bucket, key, and version ID of the uploaded file. This gives your Lambda everything it needs to read and process the file without having to parse the S3 event notification separately. Use EventBridge for processing triggers rather than S3 event notifications when you need the additional context (username, session ID, transfer status) that Transfer Family events provide but S3 events don't.

CloudWatch Logs Insights for authentication analysis

Transfer Family session logs in CloudWatch Logs contain structured JSON entries for authentication events, file operations, and session termination. Use Logs Insights to query these logs for debugging authentication failures, auditing user activity, and identifying unusual transfer patterns.

# CloudWatch Logs Insights — find authentication failures in last 24h
fields @timestamp, username, message, source_ip
| filter @logGroup = '/aws/transfer/s-0abc'
| filter message like /Authentication/
| filter outcome = 'FAILED'
| stats count() by username, source_ip
| sort count desc
| limit 20

# Find all file uploads by alice in the last week
fields @timestamp, username, fileSize, remoteFilename
| filter @logGroup = '/aws/transfer/s-0abc'
| filter username = 'alice'
| filter action = 'UPLOAD'
| sort @timestamp desc

# Find slow transfers (> 60 seconds upload duration)
fields @timestamp, username, remoteFilename, fileSize, transferBytes
| filter @logGroup = '/aws/transfer/s-0abc'
| filter action = 'CLOSE'
| filter duration > 60000  # milliseconds
| stats avg(duration) as avg_ms, max(duration) as max_ms,
        avg(fileSize) as avg_bytes by username
| sort avg_ms desc

Transfer Family log fields include: username, source_ip, session_id, protocol, action (OPEN/CLOSE/READ/WRITE/AUTH), remoteFilename, fileSize, outcome (SUCCESS/FAILED), duration (milliseconds). Use Logs Insights metric filters to create custom CloudWatch metrics from log data — for example, a metric filter counting outcome=FAILED events lets you alarm on authentication failure rate spikes without manually querying logs.

Failure modes reference

FailureSymptomFix
No metrics in AWS/Transfer namespaceCloudWatch shows no data for FilesIn/BytesIn after file transfersServer was created without a logging role — add logging role via aws transfer update-server --logging-role <arn>; metrics only appear after the role is attached (no retroactive data)
SLA alarm fires unexpectedly on weekendsMissing data alarm fires Saturday/Sunday when partner doesn't uploadUse a CloudWatch alarm schedule expression or suppress alarms outside business hours via EventBridge rule that disables/enables the alarm — or separate the alarm into weekday-only evaluation windows
EventBridge rule not triggeringFile uploads complete but Lambda not invokedTransfer Family emits events to the default event bus — verify rule is on the default bus, not a custom bus; also verify Lambda resource policy grants events.amazonaws.com invoke permission
Logs Insights returns no resultsQuery returns 0 rows despite known transfersLog group name must match exactly — Transfer Family creates the log group as /aws/transfer/<server-id>; verify with aws logs describe-log-groups --log-group-name-prefix /aws/transfer/
BytesIn includes failed transfersByte count higher than expected — counting failed partial uploadsCloudWatch BytesIn counts bytes written before transfer failure; use EventBridge File Transfer Failed events to track failed transfers separately and subtract from totals for accurate ingestion accounting