Files
dokku/tests/unit/logs-1.bats
Jose Diaz-Gonzalez b43929df27 fix: regenerate vector config on app lifecycle changes
The generated vector config is a snapshot of the app list and their sink properties, but it was only ever written by `logs:set` and `logs:vector-start`. Renaming an app left a source filtering on a label no container carries and gave the new name no source at all, so the app kept a sink with nothing feeding it. Cloning produced the same result for the clone, and destroying an app left its source and sink behind, the latter still pointing at an endpoint decommissioned along with the app. The global relabel transform embeds app names directly in generated VRL, so a rename also left behind a branch naming an app that no longer existed. Every case was silent, and the only repair was an operator running `logs:vector-start`. The `post-app-clone-setup`, `post-app-rename-setup` and `post-delete` triggers now rewrite the config, warning rather than failing so that a config write cannot abort the app operation whose state it is derived from.

Closes #8918.
2026-08-09 23:53:12 -04:00

1262 lines
42 KiB
Bash

#!/usr/bin/env bats
load test_helper
setup() {
rm "${BATS_PARENT_TMPNAME}.skip" || true
global_setup
}
teardown() {
destroy_app
# a leftover app-label-alias makes every later test's vector source filter on
# a label that dokku never applies to a container, which silently disables log
# collection for the rest of the file
dokku logs:set --global app-label-alias >/dev/null 2>/dev/null || true
dokku logs:set --global vector-image >/dev/null 2>/dev/null || true
dokku logs:set --global vector-networks >/dev/null 2>/dev/null || true
dokku logs:set --global vector-sink >/dev/null 2>/dev/null || true
dokku logs:set --global vector-cron-sink >/dev/null 2>/dev/null || true
docker network rm test-vector-net-a >/dev/null || true
docker network rm test-vector-net-b >/dev/null || true
global_teardown
}
@test "(logs) logs:help" {
run /bin/bash -c "dokku logs:help"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage log integration for an app"
}
@test "(logs) logs:report" {
run /bin/bash -c "dokku logs:report"
echo "output: $output"
echo "status: $status"
assert_output_contains "You haven't deployed any applications yet"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information"
}
@test "(logs) logs:report app" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information"
run /bin/bash -c "dokku logs:report $TEST_APP --invalid-flag 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed, valid flags: --logs-app-label-alias, --logs-computed-app-label-alias, --logs-computed-max-size, --logs-computed-vector-cron-sink, --logs-computed-vector-image, --logs-computed-vector-networks, --logs-computed-vector-sink, --logs-global-app-label-alias, --logs-global-max-size, --logs-global-vector-cron-sink, --logs-global-vector-image, --logs-global-vector-networks, --logs-global-vector-sink, --logs-max-size, --logs-vector-cron-sink, --logs-vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed" 0
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed" 0
}
@test "(logs) logs:report --global invalid flag" {
run /bin/bash -c "dokku logs:report --global --invalid-flag 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed, valid flags: --logs-computed-app-label-alias, --logs-computed-max-size, --logs-computed-vector-cron-sink, --logs-computed-vector-image, --logs-computed-vector-networks, --logs-computed-vector-sink, --logs-global-app-label-alias, --logs-global-max-size, --logs-global-vector-cron-sink, --logs-global-vector-image, --logs-global-vector-networks, --logs-global-vector-sink"
}
@test "(logs) logs:set [error]" {
run /bin/bash -c "dokku logs:set 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Please specify an app to run the command on"
run /bin/bash -c "dokku logs:set ${TEST_APP}-non-existent" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App $TEST_APP-non-existent does not exist"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "No property specified"
run /bin/bash -c "dokku logs:set $TEST_APP invalid" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid property specified, valid properties include: app-label-alias, max-size, vector-cron-sink, vector-image, vector-networks, vector-sink"
run /bin/bash -c "dokku logs:set $TEST_APP invalid value" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid property specified, valid properties include: app-label-alias, max-size, vector-cron-sink, vector-image, vector-networks, vector-sink"
run /bin/bash -c "dokku logs:set $TEST_APP vector-image timberio/vector:latest-debian 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "vector-image may only be set globally with --global"
}
@test "(logs) logs:set app" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=json"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink datadog_logs://?api_key=abc123" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "datadog_logs://?api_key=abc123"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "20m"
run /bin/bash -c "dokku logs:set $TEST_APP max-size unlimited" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unlimited"
run /bin/bash -c "dokku logs:set "$TEST_APP" max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
}
@test "(logs) logs:set equals in uri" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'loki://?endpoint=https://host&encoding[codec]=text&auth[token]=foobar%3D&auth[strategy]=bearer'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
# type: loki
# endpoint: https://host
# encoding[codec]: text
# auth[token]: foobar=
# auth[strategy]: bearer
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.strategy' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "bearer"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.token' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "foobar="
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].endpoint' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://host"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].encoding.codec' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "text"
}
@test "(logs) logs:set escaped uri" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink http://?uri=https%3A//loggerservice.com%3A1234/%3Ftoken%3Dabc1234%26type%3Dvector%26key%3Dvalue%2Bvalue2"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "http://?uri=https%3A//loggerservice.com%3A1234/%3Ftoken%3Dabc1234%26type%3Dvector%26key%3Dvalue%2Bvalue2"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].uri' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://loggerservice.com:1234/?token=abc1234&type=vector&key=value+value2"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'aws_cloudwatch_logs://?create_missing_group=true&create_missing_stream=true&group_name=groupname&encoding[codec]=json&region=sa-east-1&stream_name={{ host }}&auth[access_key_id]=KSDSIDJSAJD&auth[secret_access_key]=2932JSDJ%252BKSDSDJ'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "aws_cloudwatch_logs://?create_missing_group=true&create_missing_stream=true&group_name=groupname&encoding[codec]=json&region=sa-east-1&stream_name={{ host }}&auth[access_key_id]=KSDSIDJSAJD&auth[secret_access_key]=2932JSDJ%252BKSDSDJ"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.secret_access_key' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "2932JSDJ+KSDSDJ"
}
@test "(logs) logs:set global" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=json"
run /bin/bash -c "dokku logs:set --global vector-sink datadog_logs://?api_key=abc123" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "datadog_logs://?api_key=abc123"
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
run /bin/bash -c "dokku logs:set --global max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
run /bin/bash -c "dokku logs:set --global max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "20m"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "20m"
run /bin/bash -c "dokku logs:set --global max-size unlimited" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unlimited"
run /bin/bash -c "dokku logs:set --global max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
}
@test "(logs:report) vector-sink raw vs global" {
run create_app
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r '.\"logs-vector-sink\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r '.\"logs-global-vector-sink\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r '.\"logs-global-vector-sink\"'"
assert_success
assert_output "console://?encoding[codec]=json"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink datadog_logs://?api_key=abc"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r '.\"logs-vector-sink\"'"
assert_success
assert_output "datadog_logs://?api_key=abc"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink"
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink"
assert_success
}
@test "(logs:set) vector-cron-sink" {
run create_app
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-cron-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink console://?encoding[codec]=text"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-cron-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-cron-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=text"
# as with vector-sink, only the exact raw flag returns an unredacted value
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-vector-cron-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://redacted"
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r '.\"computed-vector-cron-sink\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=text"
# a general report redacts everything but the scheme, on both the raw and
# the computed row
run /bin/bash -c "dokku logs:report $TEST_APP 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "console://redacted" 2
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-cron-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-cron-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
@test "(logs) vector.json cron routing" {
run create_app
assert_success
# a plain sink alone must generate no transforms at all
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "jq -r '.transforms' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "null"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-source:$TEST_APP"
# adding a cron sink splits the source and rewires the plain sink
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink console://?encoding[codec]=text"
assert_success
run /bin/bash -c "jq -r '.transforms[\"docker-router:$TEST_APP\"].type' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "route"
run /bin/bash -c "jq -r '.transforms[\"docker-router:$TEST_APP\"].reroute_unmatched' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "jq -r '.transforms[\"docker-router:$TEST_APP\"].route.cron.source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "com.dokku.container-type"
run /bin/bash -c "jq -r '.transforms[\"docker-cron-remap:$TEST_APP\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku_cron_id"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-router:$TEST_APP._unmatched"
run /bin/bash -c "jq -r '.sinks[\"docker-cron-sink:$TEST_APP\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-cron-remap:$TEST_APP"
# dropping the plain sink leaves nothing to consume the unmatched branch
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink"
assert_success
run /bin/bash -c "jq -r '.transforms[\"docker-router:$TEST_APP\"].reroute_unmatched' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "null"
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink"
assert_success
# the global scope gets its own router and cron sink
run /bin/bash -c "dokku logs:set --global vector-cron-sink console://?encoding[codec]=text"
assert_success
run /bin/bash -c "jq -r '.transforms[\"docker-global-router\"].type' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "route"
run /bin/bash -c "jq -r '.sinks[\"docker-global-cron-sink\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-global-cron-remap"
run /bin/bash -c "dokku logs:set --global vector-cron-sink"
assert_success
}
@test "(logs:report) global-vector-image and global-vector-networks raw" {
run create_app
assert_success
run /bin/bash -c "dokku logs:set --global vector-image"
assert_success
run /bin/bash -c "dokku logs:report --global --format json | jq -r '.\"logs-global-vector-image\"'"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report --global --format json | jq -r '.\"logs-computed-vector-image\"'"
assert_success
assert_output_exists
run /bin/bash -c "dokku logs:set --global vector-image timberio/vector:custom"
assert_success
run /bin/bash -c "dokku logs:report --global --format json | jq -r '.\"logs-global-vector-image\"'"
assert_success
assert_output "timberio/vector:custom"
run /bin/bash -c "dokku logs:set --global vector-image"
assert_success
run /bin/bash -c "dokku logs:report --global --format json | jq -r '.\"logs-global-vector-networks\"'"
assert_success
assert_output ""
}
@test "(logs:report) does not expose deprecated logs-vector-global-* keys" {
run /bin/bash -c "dokku logs:report --global --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "logs-vector-global-image"
assert_output_not_contains "logs-vector-global-networks"
}
@test "(logs) logs:set --global vector-networks" {
docker network create test-vector-net-a >/dev/null
docker network create test-vector-net-b >/dev/null
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-networks test-vector-net-a 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "vector-networks may only be set globally with --global"
run /bin/bash -c "dokku logs:set --global vector-networks does-not-exist 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Network \"does-not-exist\" does not exist"
run /bin/bash -c "dokku logs:set --global vector-networks bridge 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "\"bridge\" is not a valid entry for vector-networks"
run /bin/bash -c "dokku logs:set --global vector-networks 'test-vector-net-a,' 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "empty entry in comma-separated list"
run /bin/bash -c "dokku logs:set --global vector-networks test-vector-net-a 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-networks"
run /bin/bash -c "dokku logs:report --global --logs-global-vector-networks 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "test-vector-net-a"
run /bin/bash -c "dokku logs:set --global vector-networks test-vector-net-a,test-vector-net-b 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-networks"
run /bin/bash -c "dokku logs:report --global --logs-global-vector-networks 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "test-vector-net-a,test-vector-net-b"
run /bin/bash -c "dokku logs:set --global vector-networks 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-networks"
run /bin/bash -c "dokku logs:report --global --logs-global-vector-networks 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
}
@test "(logs) logs:set app-label-alias" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:set --global app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting app-label-alias"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "com.dokku.app-name=$TEST_APP"
run /bin/bash -c "jq -r '.transforms' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "null"
run /bin/bash -c "dokku logs:set --global app-label-alias global_alt_name" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global_alt_name"
run /bin/bash -c "cat /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
# the source filter never moves off the label dokku actually applies, or the
# source would match no container at all and silently collect nothing
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "com.dokku.app-name=$TEST_APP"
run /bin/bash -c "jq -r '.transforms[\"docker-relabel:$TEST_APP\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output '.label."global_alt_name" = del(.label."com.dokku.app-name")'
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-relabel:$TEST_APP"
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias alt_name" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "alt_name"
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "com.dokku.app-name=$TEST_APP"
run /bin/bash -c "jq -r '.transforms[\"docker-relabel:$TEST_APP\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output '.label."alt_name" = del(.label."com.dokku.app-name")'
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(logs:set) app-label-alias rejects an unusable label key" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias 'not a label' 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid app-label-alias value"
run /bin/bash -c "dokku logs:set --global app-label-alias '_leading_underscore' 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid app-label-alias value"
}
# an app whose own alias differs from the global one is collected by the global
# source too, so the global pipeline carries a branch for it
@test "(logs) vector.json global relabel honors a per-app alias" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:set --global app-label-alias global_alt_name"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias app_alt_name"
assert_success
run /bin/bash -c "jq -r '.transforms[\"docker-global-relabel\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "if app == \"$TEST_APP\""
assert_output_contains '.label."app_alt_name" = del(.label."com.dokku.app-name")'
assert_output_contains '.label."global_alt_name" = del(.label."com.dokku.app-name")'
run /bin/bash -c "jq -r '.sinks[\"docker-global-sink\"].inputs[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "docker-global-relabel"
# a per-app alias matching the global one needs no branch of its own
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias global_alt_name"
assert_success
run /bin/bash -c "jq -r '.transforms[\"docker-global-relabel\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output '.label."global_alt_name" = del(.label."com.dokku.app-name")'
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias"
assert_success
run /bin/bash -c "dokku logs:set --global app-label-alias"
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink"
assert_success
}
@test "(logs) vector.json drops a destroyed app" {
local DESTROYED_APP="${TEST_APP}-destroyed"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:create $DESTROYED_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:set $DESTROYED_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "jq -e '.sources | has(\"docker-source:$DESTROYED_APP\")' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --force apps:destroy $DESTROYED_APP"
echo "output: $output"
echo "status: $status"
assert_success
# an orphaned sink keeps pointing at an endpoint decommissioned with the app
run /bin/bash -c "jq -e '(.sources | has(\"docker-source:$DESTROYED_APP\")) or (.sinks | has(\"docker-sink:$DESTROYED_APP\"))' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "jq -e '.sources | has(\"docker-source:$TEST_APP\")' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(logs) vector.json follows a renamed app" {
local RENAMED_APP="${TEST_APP}-renamed"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku apps:rename --skip-deploy $TEST_APP $RENAMED_APP"
echo "output: $output"
echo "status: $status"
assert_success
# the sink property follows the app, so a stale config leaves the app with a
# sink and no source feeding it
run /bin/bash -c "dokku logs:report $RENAMED_APP --logs-computed-vector-sink"
echo "output: $output"
echo "status: $status"
assert_output "console://redacted"
run /bin/bash -c "jq -r '.sources[\"docker-source:$RENAMED_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_output "com.dokku.app-name=$RENAMED_APP"
run /bin/bash -c "jq -e '(.sources | has(\"docker-source:$TEST_APP\")) or (.sinks | has(\"docker-sink:$TEST_APP\"))' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_failure
TEST_APP="$RENAMED_APP"
}
@test "(logs) vector.json adds a source for a cloned app" {
local CLONE_APP="${TEST_APP}-clone"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku apps:clone --skip-deploy $TEST_APP $CLONE_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "jq -r '.sources[\"docker-source:$CLONE_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_output "com.dokku.app-name=$CLONE_APP"
run /bin/bash -c "jq -e '.sinks | has(\"docker-sink:$CLONE_APP\")' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "jq -e '.sources | has(\"docker-source:$TEST_APP\")' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --force apps:destroy $CLONE_APP"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(logs) vector.json global relabel follows a renamed app" {
local RENAMED_APP="${TEST_APP}-renamed"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias app_alt_name"
assert_success
run /bin/bash -c "dokku apps:rename --skip-deploy $TEST_APP $RENAMED_APP"
echo "output: $output"
echo "status: $status"
assert_success
# the relabel branches are generated VRL with app names baked in, so a rename
# leaves a branch naming an app that no longer exists
run /bin/bash -c "jq -r '.transforms[\"docker-global-relabel\"].source' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "if app == \"$RENAMED_APP\""
assert_output_not_contains "if app == \"$TEST_APP\""
TEST_APP="$RENAMED_APP"
}
@test "(logs) logs:set max-size with alternate log-driver daemon" {
if [[ "$REMOTE_CONTAINERS" == "true" ]]; then
skip "skipping due non-existent docker service in remote dev container"
fi
if [[ ! -f /etc/docker/daemon.json ]]; then
echo "{}" >/etc/docker/daemon.json
fi
driver="$(jq -r '."log-driver"' /etc/docker/daemon.json)"
local TMP_FILE=$(mktemp "/tmp/${DOKKU_DOMAIN}.XXXX")
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m --restart=on-failure:10"
DRIVER="journald" jq '."log-driver" = env.DRIVER' <"/etc/docker/daemon.json" >"$TMP_FILE"
mv "$TMP_FILE" /etc/docker/daemon.json
sudo service docker restart
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--restart=on-failure:10"
if [[ "$driver" = "null" ]]; then
DRIVER="$driver" jq 'del(."log-driver")' <"/etc/docker/daemon.json" >"$TMP_FILE"
else
DRIVER="$driver" jq '."log-driver" = env.DRIVER' <"/etc/docker/daemon.json" >"$TMP_FILE"
fi
mv "$TMP_FILE" /etc/docker/daemon.json
sudo service docker restart
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m --restart=on-failure:10"
}
@test "(logs) logs:set max-size with alternate log-driver" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m --restart=on-failure:10"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=local" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m --restart=on-failure:10"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=json-file" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m --restart=on-failure:10"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=journald" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--restart=on-failure:10"
}
@test "(logs:report) emits new stripped JSON keys alongside legacy" {
run create_app
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r 'has(\"vector-sink\") and has(\"logs-vector-sink\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r 'has(\"global-vector-sink\") and has(\"logs-global-vector-sink\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r 'has(\"computed-vector-sink\") and has(\"logs-computed-vector-sink\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku logs:report $TEST_APP --format json | jq -r 'has(\"max-size\") and has(\"logs-max-size\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku logs:report --global --format json | jq -r 'has(\"global-vector-image\") and has(\"logs-global-vector-image\")'"
assert_success
assert_output "true"
}