All Galleon subsystems write a single structured log stream to stdout — JSON format, one record per line. Rotation and delivery to a log storage system are the deployment platform’s concern.
Configuration
The logging configuration block:
| Key | Default | Purpose |
|---|---|---|
level | info | The Galleon log threshold: debug, info, warn, error |
format | json | json or text |
registry_level | warn | A separate threshold for the records about container image operations |
The audit events of container image operations (manifest, blob, and tag uploads
and deletions) are always written, regardless of registry_level.
Access log
Every request writes one msg="http request" record with the fields:
source (the subsystem), method, path, status, size,
user, client_ip, duration, the database time and query count,
and the trailing request_id.
user carries the authenticated account;
a request without successful authentication shows - there.
Galleon returns the same identifier to the client in the X-Request-ID header.
It finds every record of one request in the log.
client_ip behind a reverse proxy is correct only with trust configured
(Reverse proxy).
The errors of the HTTP server itself are logged with the server.http source at
the warn level. When Galleon serves HTTPS itself, failed TLS handshakes land
in that source (TLS).
The fields that appear only on problem traffic:
sqlstate— the request hit a PostgreSQL error;served_stale=true— a proxy repository served a stale copy because the external registry did not respond;deny_reason— an authentication or access denial; the value dictionary is below.
The attempted_user field is the login the client presented: the credentials
were rejected, or not checked because the request was refused earlier. The ?
value means a non-Basic authorization or an empty login. Look for failed
sign-ins by this field: user shows - on such records. The field appears on
normal traffic as well, for example when monitoring polls an open endpoint with
credentials.
Denial reasons
The deny_reason field explains every denial without changing the client response
(response codes do not reveal the existence of others’ repositories):
| Value | Reason |
|---|---|
no_credentials | A request without credentials where they are mandatory |
bad_credentials | Credentials were presented and rejected |
anonymous_disabled | Anonymous access is off |
anonymous_forbidden | The anonymous role lacks a privilege |
forbidden | The user lacks a privilege on the repository |
admin_required | An administrative privilege is missing |
anon_no_admin | An anonymous container image request that requires administrative rights |
password_change_required | Blocked until the forced password change |
repository_not_found | The target repository was not found; also stamped on a 404 answered before the credential check |
repository_name_invalid | The repository name could not be parsed, so no lookup was made |
wrong_format | The repository exists but has a different format |
monitoring_ip_denied | An address outside monitoring_allowlist |
upstream_manually_blocked | Requests to the external registry are frozen manually |
upstream_auto_blocked | Requests are paused by auto-blocking |
A 401/403 record without deny_reason indicates an infrastructure failure:
check the err and sqlstate fields. A 404 on a repository carries a reason
as well; only the answers of a repository taken out of service and the refusals
of a malformed request go without one.
Audit events
Administrative and domain events are written at the info level:
- artifact publications —
msg="<FORMAT> artifact published"records with the coordinates and repository, one per artifact; - container image operations — manifest, blob, and tag uploads and deletions;
- repository cache invalidation (
source=audit.repository); - bootstrap administrator creation, creation of the starter set of repositories, garbage collection cycle summaries, external registry connection state changes.
Secrets never reach the log at any level:
authorization header values, passwords, tokens, and body contents are not logged.
Control characters and invalid UTF-8 in client-supplied values
(the path, headers, file names) are replaced with ? in the log.