@@ -283,6 +283,7 @@ void duplicate_config(struct config *dst, struct config *src)
283283 case CONF_ENUM_WEB_THEME :
284284 case CONF_ENUM_TEMP_UNIT :
285285 case CONF_ENUM_BLOCKING_EDNS_MODE :
286+ case CONF_ENUM_LOG_DESTINATION :
286287 case CONF_STRUCT_IN_ADDR :
287288 case CONF_STRUCT_IN6_ADDR :
288289 case CONF_ALL_DEBUG_BOOL :
@@ -321,6 +322,7 @@ bool compare_config_item(const enum conf_type t, const union conf_value *val1, c
321322 case CONF_ENUM_WEB_THEME :
322323 case CONF_ENUM_TEMP_UNIT :
323324 case CONF_ENUM_BLOCKING_EDNS_MODE :
325+ case CONF_ENUM_LOG_DESTINATION :
324326 case CONF_STRUCT_IN_ADDR :
325327 case CONF_STRUCT_IN6_ADDR :
326328 case CONF_ALL_DEBUG_BOOL :
@@ -377,6 +379,7 @@ void free_config(struct config *conf, const bool terminating)
377379 case CONF_ENUM_WEB_THEME :
378380 case CONF_ENUM_TEMP_UNIT :
379381 case CONF_ENUM_BLOCKING_EDNS_MODE :
382+ case CONF_ENUM_LOG_DESTINATION :
380383 case CONF_STRUCT_IN_ADDR :
381384 case CONF_STRUCT_IN6_ADDR :
382385 case CONF_ALL_DEBUG_BOOL :
@@ -1370,7 +1373,7 @@ void initConfig(struct config *conf)
13701373 conf -> files .pcap .c = validate_filepath_empty ;
13711374
13721375 // sub-struct files.log
1373- // conf->files.log.ftl is set in a separate function (getLogFilePath)
1376+ // conf->files.log.ftl and conf->files.log.destination is set in a separate function (getLogFilePath)
13741377
13751378 conf -> files .log .dnsmasq .k = "files.log.dnsmasq" ;
13761379 conf -> files .log .dnsmasq .h = "The log file used by the embedded dnsmasq DNS server" ;
@@ -1986,6 +1989,20 @@ static bool getLogFilePathENV(void)
19861989 return true;
19871990}
19881991
1992+ static bool getLogDestinationENV (void )
1993+ {
1994+ const char * val = getenv (FTLCONF_PREFIX "files_log_destination" );
1995+ if (val == NULL || * val == '\0' )
1996+ return false;
1997+
1998+ const int dest = get_log_destination_val (val );
1999+ if (dest == -1 )
2000+ return false;
2001+
2002+ config .files .log .destination .v .log_destination = dest ;
2003+ return true;
2004+ }
2005+
19892006bool getLogFilePath (bool try_read )
19902007{
19912008 // Initialize memory
@@ -2001,9 +2018,38 @@ bool getLogFilePath(bool try_read)
20012018 config .files .log .ftl .c = validate_filepath ;
20022019 config .files .log .ftl .f = FLAG_FTL_LOG ;
20032020
2004- // Try sources in priority order: ENV > TOML > legacy
2005- if (try_read && !getLogFilePathENV () && !getLogFilePathTOML ())
2006- return getLogFilePathLegacy (& config , NULL );
2021+ // Initialize log destination
2022+ config .files .log .destination .k = "files.log.destination" ;
2023+ config .files .log .destination .h = "Where to write FTL, webserver and dnsmasq log output" ;
2024+ {
2025+ struct enum_options log_destination [] =
2026+ {
2027+ { "FILE" , "Write logs to the configured log files" },
2028+ { "JSON" , "Write logs as structured JSON to stdout" }
2029+ };
2030+ CONFIG_ADD_ENUM_OPTIONS (config .files .log .destination .a , log_destination );
2031+ }
2032+ config .files .log .destination .t = CONF_ENUM_LOG_DESTINATION ;
2033+ config .files .log .destination .f = FLAG_READ_ONLY ;
2034+ config .files .log .destination .d .log_destination = LOG_DEST_FILE ;
2035+ config .files .log .destination .c = validate_stub ;
2036+
2037+ // Read log file path: ENV > TOML > legacy
2038+ // ENV is always checked so it works during early init (try_read=false).
2039+ // When try_read is true, TOML and legacy are also checked. Since ENV
2040+ // runs last, it takes precedence over TOML and legacy if set.
2041+ if (try_read )
2042+ {
2043+ if (!getLogFilePathTOML ())
2044+ getLogFilePathLegacy (& config , NULL );
2045+ }
2046+ getLogFilePathENV ();
2047+
2048+ // Read log destination: ENV > TOML
2049+ // Same priority logic: ENV runs last and wins if set.
2050+ if (try_read )
2051+ getLogDestinationTOML ();
2052+ getLogDestinationENV ();
20072053
20082054 return true;
20092055}
@@ -2055,6 +2101,7 @@ const char * __attribute__ ((const)) get_conf_type_str(const enum conf_type type
20552101 case CONF_ENUM_WEB_THEME :
20562102 case CONF_ENUM_TEMP_UNIT :
20572103 case CONF_ENUM_BLOCKING_EDNS_MODE :
2104+ case CONF_ENUM_LOG_DESTINATION :
20582105 return "enum (string)" ;
20592106 case CONF_ENUM_PRIVACY_LEVEL :
20602107 return "enum (unsigned integer)" ;
0 commit comments