Skip to content

Commit c7576e2

Browse files
committed
Use structed json logging
Signed-off-by: yubiuser <github@yubiuser.dev>
1 parent fa377e2 commit c7576e2

2 files changed

Lines changed: 89 additions & 68 deletions

File tree

src/bash_functions.sh

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -28,102 +28,130 @@ setFTLConfigValue() {
2828
pihole-FTL --config "${1}" "${2}" >/dev/null
2929
}
3030

31+
__timestamp(){
32+
date "+%Y%m%dT%H%M%S"
33+
}
34+
35+
__log(){
36+
local level="$1"
37+
local service="$2"
38+
local msg="$3"
39+
40+
# Check if msg is valid JSON - if so, use --argjson to avoid escaping
41+
if echo "$msg" | jq empty 2>/dev/null; then
42+
echo '{}' | \
43+
jq --monochrome-output \
44+
--compact-output \
45+
--raw-output \
46+
--arg timestamp "$(__timestamp)" \
47+
--arg level "$level" \
48+
--arg service "$service" \
49+
--argjson msg "$msg" \
50+
'.timestamp=$timestamp|.log_level=$level|.service=$service|.message=$msg'
51+
else
52+
echo '{}' | \
53+
jq --monochrome-output \
54+
--compact-output \
55+
--raw-output \
56+
--arg timestamp "$(__timestamp)" \
57+
--arg level "$level" \
58+
--arg service "$service" \
59+
--arg msg "$msg" \
60+
'.timestamp=$timestamp|.log_level=$level|.service=$service|.message=$msg'
61+
fi
62+
}
63+
3164
set_uid_gid() {
3265

33-
echo " [i] Setting up user & group for the pihole user"
66+
__log "INFO" "pihole-docker" "Setting up user & group for the pihole user"
3467

3568
currentUid=$(id -u pihole)
3669

3770
# If PIHOLE_UID is set, modify the pihole group's id to match
3871
if [ -n "${PIHOLE_UID}" ]; then
3972
if [[ ${currentUid} -ne ${PIHOLE_UID} ]]; then
40-
echo " [i] Changing ID for user: pihole (${currentUid} => ${PIHOLE_UID})"
73+
__log "INFO" "pihole-docker" "Changing ID for user: pihole (${currentUid} => ${PIHOLE_UID})"
4174
usermod -o -u "${PIHOLE_UID}" pihole
4275
else
43-
echo " [i] ID for user pihole is already ${PIHOLE_UID}, no need to change"
76+
__log "INFO" "pihole-docker" "ID for user pihole is already ${PIHOLE_UID}, no need to change"
4477
fi
4578
else
46-
echo " [i] PIHOLE_UID not set in environment, using default (${currentUid})"
79+
__log "INFO" "pihole-docker" "PIHOLE_UID not set in environment, using default (${currentUid})"
4780
fi
4881

4982
currentGid=$(id -g pihole)
5083

5184
# If PIHOLE_GID is set, modify the pihole group's id to match
5285
if [ -n "${PIHOLE_GID}" ]; then
5386
if [[ ${currentGid} -ne ${PIHOLE_GID} ]]; then
54-
echo " [i] Changing ID for group: pihole (${currentGid} => ${PIHOLE_GID})"
87+
__log "INFO" "pihole-docker" "Changing ID for group: pihole (${currentGid} => ${PIHOLE_GID})"
5588
groupmod -o -g "${PIHOLE_GID}" pihole
5689
else
57-
echo " [i] ID for group pihole is already ${PIHOLE_GID}, no need to change"
90+
__log "INFO" "pihole-docker" "ID for group pihole is already ${PIHOLE_GID}, no need to change"
5891
fi
5992
else
60-
echo " [i] PIHOLE_GID not set in environment, using default (${currentGid})"
93+
__log "INFO" "pihole-docker" "PIHOLE_GID not set in environment, using default (${currentGid})"
6194
fi
62-
echo ""
6395
}
6496

6597
install_additional_packages() {
6698
if [ -n "${ADDITIONAL_PACKAGES}" ]; then
67-
echo " [i] Additional packages requested: ${ADDITIONAL_PACKAGES}"
68-
echo " [i] Fetching APK repository metadata."
99+
__log "INFO" "pihole-docker" "Additional packages requested: ${ADDITIONAL_PACKAGES}"
100+
__log "INFO" "pihole-docker" "Fetching APK repository metadata."
69101
if ! apk update; then
70-
echo " [i] Failed to fetch APK repository metadata."
102+
__log "ERROR" "pihole-docker" "Failed to fetch APK repository metadata."
71103
else
72-
echo " [i] Installing additional packages: ${ADDITIONAL_PACKAGES}."
104+
__log "INFO" "pihole-docker" "Installing additional packages: ${ADDITIONAL_PACKAGES}."
73105
# shellcheck disable=SC2086
74106
if ! apk add --no-cache ${ADDITIONAL_PACKAGES}; then
75-
echo " [i] Failed to install additional packages."
107+
__log "ERROR" "pihole-docker" "Failed to install additional packages."
76108
fi
77109
fi
78-
echo ""
79110
fi
80111
}
81112

82113
start_cron() {
83-
echo " [i] Starting crond for scheduled scripts. Randomizing times for gravity and update checker"
114+
__log "INFO" "pihole-docker" "Starting crond for scheduled scripts. Randomizing times for gravity and update checker"
84115
# Randomize gravity update time
85116
sed -i "s/59 1 /$((1 + RANDOM % 58)) $((3 + RANDOM % 2))/" /crontab.txt
86117
# Randomize update checker time
87118
sed -i "s/59 17/$((1 + RANDOM % 58)) $((12 + RANDOM % 8))/" /crontab.txt
88119
if ! /usr/bin/crontab /crontab.txt; then
89-
echo " [!] Failed to install crontab - scheduled tasks (gravity, update checker) will not run"
120+
__log "ERROR" "pihole-docker" "Failed to install crontab - scheduled tasks (gravity, update checker) will not run"
90121
fi
91122

92123
/usr/sbin/crond
93-
echo ""
94124
}
95125

96126
install_logrotate() {
97127
# Install the logrotate config file - this is done already in Dockerfile
98128
# but if a user has mounted a volume over /etc/pihole, it will have been lost
99129
# pihole-FTL-prestart.sh will set the ownership of the file to root:root
100-
echo " [i] Ensuring logrotate script exists in /etc/pihole"
130+
__log "INFO" "pihole-docker" "Ensuring logrotate script exists in /etc/pihole"
101131
install -Dm644 -t /etc/pihole /etc/.pihole/advanced/Templates/logrotate
102-
echo ""
103132
}
104133

105134
migrate_gravity() {
106-
echo " [i] Gravity migration checks"
135+
__log "INFO" "pihole-docker" "Gravity migration checks"
107136
gravityDBfile=$(getFTLConfigValue files.gravity)
108137

109138
if [[ ! -f /etc/pihole/adlists.list ]]; then
110-
echo " [i] No adlist file found, creating one with a default blocklist"
139+
__log "INFO" "pihole-docker" "No adlist file found, creating one with a default blocklist"
111140
echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >/etc/pihole/adlists.list
112141
fi
113142

114143
if [ ! -f "${gravityDBfile}" ]; then
115-
echo " [i] ${gravityDBfile} does not exist (Likely due to a fresh volume). This is a required file for Pi-hole to operate."
116-
echo " [i] Gravity will now be run to create the database"
144+
__log "INFO" "pihole-docker" "${gravityDBfile} does not exist (Likely due to a fresh volume). This is a required file for Pi-hole to operate."
145+
__log "INFO" "pihole-docker" "Gravity will now be run to create the database"
117146
pihole -g
118147
else
119-
echo " [i] Existing gravity database found - schema will be upgraded if necessary"
148+
__log "INFO" "pihole-docker" "Existing gravity database found - schema will be upgraded if necessary"
120149
# source the migration script and run the upgrade function
121150
source /etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh
122151
local upgradeOutput
123152
upgradeOutput=$(upgrade_gravityDB "${gravityDBfile}" "/etc/pihole")
124-
printf "%b" "${upgradeOutput}\\n" | sed 's/^/ /'
153+
__log "INFO" "pihole-docker" "Gravity DB migration output: ${upgradeOutput}"
125154
fi
126-
echo ""
127155
}
128156

129157
# shellcheck disable=SC2034
@@ -142,7 +170,7 @@ ftl_config() {
142170

143171
# If getFTLConfigValue "dns.upstreams" returns [], default to Google's DNS server
144172
if [[ $(getFTLConfigValue "dns.upstreams") == "[]" ]]; then
145-
echo " [i] No DNS upstream set in environment or config file, defaulting to Google DNS"
173+
__log "INFO" "pihole-docker" "No DNS upstream set in environment or config file, defaulting to Google DNS"
146174
setFTLConfigValue "dns.upstreams" "[\"8.8.8.8\", \"8.8.4.4\"]"
147175
fi
148176

@@ -154,7 +182,7 @@ migrate_v5_configs() {
154182
# During migration, their content is copied into the new single source of
155183
# truth file /etc/pihole/pihole.toml and the old files are moved away to
156184
# avoid conflicts with other services on this system
157-
echo " [i] Migrating dnsmasq configuration files"
185+
__log "INFO" "pihole-docker" "Migrating dnsmasq configuration files"
158186
V6_CONF_MIGRATION_DIR="/etc/pihole/migration_backup_v6"
159187
# Create target directory and make it owned by pihole:pihole
160188
mkdir -p "${V6_CONF_MIGRATION_DIR}"
@@ -169,7 +197,6 @@ migrate_v5_configs() {
169197

170198
mv /etc/dnsmasq.d/0{1,2,4,5}-pihole*.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true
171199
mv /etc/dnsmasq.d/06-rfc6761.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true
172-
echo ""
173200

174201
# Finally, after everything is in place, we can create the new config file
175202
# /etc/pihole/pihole.toml
@@ -184,27 +211,25 @@ migrate_v5_configs() {
184211
# We suppress the message about environment variables as these will be set on FTL's first real start
185212
printf "%b" "${FTLoutput}\\n" | sed 's/^/ /' | sed 's/ Migrating config to Pi-hole v6.0 format/ [i] Migrating config to Pi-hole v6.0 format/' | sed 's/- 0 entries are forced through environment//'
186213

187-
# Print a blank line for separation
188-
echo ""
189214
}
190215

191216
setup_web_password() {
192217
if [ -z "${FTLCONF_webserver_api_password+x}" ] && [ -n "${WEBPASSWORD_FILE}" ] && [ -r "/run/secrets/${WEBPASSWORD_FILE}" ]; then
193-
echo " [i] Setting FTLCONF_webserver_api_password from file"
218+
__log "INFO" "pihole-docker" "Setting FTLCONF_webserver_api_password from file"
194219
export FTLCONF_webserver_api_password=$(<"/run/secrets/${WEBPASSWORD_FILE}")
195220
fi
196221

197222
# If FTLCONF_webserver_api_password is not set
198223
if [ -z "${FTLCONF_webserver_api_password+x}" ]; then
199224
# Is this already set to something other than blank (default) in FTL's config file? (maybe in a volume mount)
200225
if [[ $(pihole-FTL --config webserver.api.pwhash) ]]; then
201-
echo " [i] Password already set in config file"
226+
__log "INFO" "pihole-docker" "Password already set in config file"
202227
return
203228
else
204229
# If we are here, the password is set in neither the environment nor the config file
205230
# We will generate a random password.
206231
RANDOMPASSWORD=$(tr -dc _A-Z-a-z-0-9 </dev/urandom | head -c 8)
207-
echo " [i] No password set in environment or config file, assigning random password: $RANDOMPASSWORD"
232+
__log "INFO" "pihole-docker" "No password set in environment or config file, assigning random password: $RANDOMPASSWORD"
208233

209234
# Explicitly turn off bash printing when working with secrets
210235
{ set +x; } 2>/dev/null
@@ -218,15 +243,15 @@ setup_web_password() {
218243
fi
219244
fi
220245
else
221-
echo " [i] Assigning password defined by Environment Variable"
246+
__log "INFO" "pihole-docker" "Assigning password defined by Environment Variable"
222247
fi
223248
}
224249

225250
fix_capabilities() {
226251
# Testing on Docker 20.10.14 with no caps set shows the following caps available to the container:
227252
# Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=ep
228253
# FTL can also use CAP_NET_ADMIN and CAP_SYS_NICE. If we try to set them when they haven't been explicitly enabled, FTL will not start. Test for them first:
229-
echo " [i] Setting capabilities on pihole-FTL where possible"
254+
__log "INFO" "pihole-docker" "Setting capabilities on pihole-FTL where possible"
230255
capsh --has-p=cap_chown 2>/dev/null && CAP_STR+=',CAP_CHOWN'
231256
capsh --has-p=cap_net_bind_service 2>/dev/null && CAP_STR+=',CAP_NET_BIND_SERVICE'
232257
capsh --has-p=cap_net_raw 2>/dev/null && CAP_STR+=',CAP_NET_RAW'
@@ -236,30 +261,28 @@ fix_capabilities() {
236261

237262
if [[ ${CAP_STR} ]]; then
238263
# We have the (some of) the above caps available to us - apply them to pihole-FTL
239-
echo " [i] Applying the following caps to pihole-FTL:"
240264
IFS=',' read -ra CAPS <<<"${CAP_STR:1}"
241-
for i in "${CAPS[@]}"; do
242-
echo " * ${i}"
243-
done
265+
# Build JSON array from capabilities
266+
CAPS_JSON=$(printf '%s\n' "${CAPS[@]}" | jq -R . | jq -s '{"applied_capabilities": .}')
267+
__log "INFO" "pihole-docker" "$CAPS_JSON"
244268

245269
setcap "${CAP_STR:1}"+ep "$(which pihole-FTL)" || ret=$?
246270

247271
if [[ $DHCP_READY == false ]] && [[ $FTLCONF_dhcp_active == true ]]; then
248272
# DHCP is requested but NET_ADMIN is not available.
249-
echo "ERROR: DHCP requested but NET_ADMIN is not available. DHCP will not be started."
250-
echo " Please add cap_net_admin to the container's capabilities or disable DHCP."
273+
__log "ERROR" "pihole-docker" "DHCP requested but NET_ADMIN is not available. DHCP will not be started."
274+
__log "INFO" "pihole-docker" " Please add cap_net_admin to the container's capabilities or disable DHCP."
251275
setFTLConfigValue dhcp.active false
252276
fi
253277

254278
if [[ $ret -ne 0 && "${DNSMASQ_USER:-pihole}" != "root" ]]; then
255-
echo " [!] ERROR: Unable to set capabilities for pihole-FTL. Cannot run as non-root."
256-
echo " If you are seeing this error, please set the environment variable 'DNSMASQ_USER' to the value 'root'"
279+
__log "ERROR" "pihole-docker" "Unable to set capabilities for pihole-FTL. Cannot run as non-root."
280+
__log "ERROR" "pihole-docker" "If you are seeing this error, please set the environment variable 'DNSMASQ_USER' to the value 'root'"
257281
exit 1
258282
fi
259283
else
260-
echo " [!] ERROR: Unable to set capabilities for pihole-FTL."
261-
echo " Please ensure that the container has the required capabilities."
284+
__log "ERROR" "pihole-docker" "Unable to set capabilities for pihole-FTL."
285+
__log "ERROR" "pihole-docker" "Please ensure that the container has the required capabilities."
262286
exit 1
263287
fi
264-
echo ""
265288
}

src/start.sh

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ start() {
2323
# If the file /etc/pihole/setupVars.conf exists, but /etc/pihole/pihole.toml does not, then we are migrating v5->v6
2424
# FTL Will handle the migration of the config files
2525
if [[ -f /etc/pihole/setupVars.conf && ! -f /etc/pihole/pihole.toml ]]; then
26-
echo " [i] v5 files detected that have not yet been migrated to v6"
27-
echo ""
26+
__log "INFO" "pihole-docker" "v5 files detected that have not yet been migrated to v6"
2827
migrate_v5_configs
2928
fi
3029

@@ -36,7 +35,7 @@ start() {
3635
set_uid_gid
3736

3837
# Configure FTL with any environment variables if needed
39-
echo " [i] Starting FTL configuration"
38+
__log "INFO" "pihole-docker" "Starting FTL configuration"
4039
ftl_config
4140

4241
# Install additional packages inside the container if requested
@@ -51,7 +50,7 @@ start() {
5150
#migrate Gravity Database if needed:
5251
migrate_gravity
5352

54-
echo " [i] pihole-FTL pre-start checks"
53+
__log "INFO" "pihole-docker" "pihole-FTL pre-start checks"
5554
# Run the post stop script to cleanup any remaining artifacts from a previous run
5655
sh /opt/pihole/pihole-FTL-poststop.sh
5756

@@ -65,8 +64,7 @@ start() {
6564
local startFrom
6665
startFrom=$(stat -c%s "${FTLlogFile}")
6766

68-
echo " [i] Starting pihole-FTL ($FTL_CMD) as ${DNSMASQ_USER}"
69-
echo ""
67+
__log "INFO" "pihole-docker" "Starting pihole-FTL as user ${DNSMASQ_USER}"
7068

7169
capsh --user="${DNSMASQ_USER}" --keep=1 -- -c "/usr/bin/pihole-FTL $FTL_CMD >/dev/null" &
7270
# Notes on above:
@@ -79,22 +77,26 @@ start() {
7977

8078
# Wait for FTL to start by monitoring the FTL log file for the "FTL started" line
8179
if ! timeout 30 tail -F -c +$((startFrom + 1)) -- "${FTLlogFile}" | grep -q '########## FTL started'; then
82-
echo " [!] ERROR: Did not find 'FTL started' message in ${FTLlogFile} in 30 seconds, stopping container"
80+
__log "ERROR" "pihole-docker" "Did not find 'FTL started' message in ${FTLlogFile} in 30 seconds, stopping container"
8381
exit 1
8482
fi
8583

8684
pihole updatechecker
87-
local versionsOutput
88-
versionsOutput=$(pihole -v)
89-
echo " [i] Version info:"
90-
printf "%b" "${versionsOutput}\\n" | sed 's/^/ /'
91-
echo ""
85+
86+
# Get version information from API endpoint
87+
local versionJson
88+
versionJson=$(pihole api info/version | jq -c '{
89+
core: .version.core.local | {version, branch, hash},
90+
web: .version.web.local | {version, branch, hash},
91+
ftl: .version.ftl.local | {version, branch, hash, date}
92+
}')
93+
__log "INFO" "pihole-docker" "$versionJson"
9294

9395
if [ "${TAIL_FTL_LOG:-1}" -eq 1 ]; then
9496
# Start tailing the FTL log file from the EOF position we recorded on container start
9597
tail -F -c +$((startFrom + 1)) -- "${FTLlogFile}" &
9698
else
97-
echo " [i] FTL log output is disabled. Remove the Environment variable TAIL_FTL_LOG, or set it to 1 to enable FTL log output."
99+
__log "INFO" "pihole-docker" "FTL log output is disabled. Remove the Environment variable TAIL_FTL_LOG, or set it to 1 to enable FTL log output."
98100
fi
99101

100102
# Wait for the capsh process (which spawned FTL) to finish
@@ -116,8 +118,8 @@ stop() {
116118
if [ -z "${FTL_EXIT_CODE}" ]; then
117119
TRAP_TRIGGERED=1
118120
echo ""
119-
echo " [i] Container stop requested..."
120-
echo " [i] pihole-FTL is running - Attempting to shut it down cleanly"
121+
__log "INFO" "pihole-docker" "Container stop requested..."
122+
__log "INFO" "pihole-docker" "pihole-FTL is running - Attempting to shut it down cleanly"
121123
echo ""
122124
killall --signal 15 pihole-FTL
123125

@@ -135,12 +137,8 @@ stop() {
135137

136138
sh /opt/pihole/pihole-FTL-poststop.sh
137139

138-
echo ""
139-
echo " [i] pihole-FTL exited with status $FTL_EXIT_CODE"
140-
echo ""
141-
echo " [i] Container will now stop or restart depending on your restart policy"
142-
echo " https://docs.docker.com/engine/containers/start-containers-automatically/#use-a-restart-policy"
143-
echo ""
140+
__log "INFO" "pihole-docker" "pihole-FTL exited with status ${FTL_EXIT_CODE}"
141+
__log "INFO" "pihole-docker" "Container will now stop or restart depending on your restart policy - https://docs.docker.com/engine/containers/start-containers-automatically/#use-a-restart-policy"
144142

145143
exit "${FTL_EXIT_CODE}"
146144

0 commit comments

Comments
 (0)