@@ -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 :
@@ -1362,7 +1365,7 @@ void initConfig(struct config *conf)
13621365 conf -> files .pcap .c = validate_filepath_empty ;
13631366
13641367 // sub-struct files.log
1365- // conf->files.log.ftl is set in a separate function (getLogFilePath)
1368+ // conf->files.log.ftl and conf->files.log.destination is set in a separate function (getLogFilePath)
13661369
13671370 conf -> files .log .dnsmasq .k = "files.log.dnsmasq" ;
13681371 conf -> files .log .dnsmasq .h = "The log file used by the embedded dnsmasq DNS server" ;
@@ -1964,6 +1967,20 @@ static bool getLogFilePathENV(void)
19641967 return true;
19651968}
19661969
1970+ static bool getLogDestinationENV (void )
1971+ {
1972+ const char * val = getenv (FTLCONF_PREFIX "files_log_destination" );
1973+ if (val == NULL || * val == '\0' )
1974+ return false;
1975+
1976+ const int dest = get_log_destination_val (val );
1977+ if (dest == -1 )
1978+ return false;
1979+
1980+ config .files .log .destination .v .log_destination = dest ;
1981+ return true;
1982+ }
1983+
19671984bool getLogFilePath (bool try_read )
19681985{
19691986 // Initialize memory
@@ -1979,9 +1996,38 @@ bool getLogFilePath(bool try_read)
19791996 config .files .log .ftl .c = validate_filepath ;
19801997 config .files .log .ftl .f = FLAG_FTL_LOG ;
19811998
1982- // Try sources in priority order: ENV > TOML > legacy
1983- if (try_read && !getLogFilePathENV () && !getLogFilePathTOML ())
1984- return getLogFilePathLegacy (& config , NULL );
1999+ // Initialize log destination
2000+ config .files .log .destination .k = "files.log.destination" ;
2001+ config .files .log .destination .h = "Where to write FTL, webserver and dnsmasq log output" ;
2002+ {
2003+ struct enum_options log_destination [] =
2004+ {
2005+ { "FILE" , "Write logs to the configured log files" },
2006+ { "JSON" , "Write logs as structured JSON to stdout" }
2007+ };
2008+ CONFIG_ADD_ENUM_OPTIONS (config .files .log .destination .a , log_destination );
2009+ }
2010+ config .files .log .destination .t = CONF_ENUM_LOG_DESTINATION ;
2011+ config .files .log .destination .f = FLAG_READ_ONLY ;
2012+ config .files .log .destination .d .log_destination = LOG_DEST_FILE ;
2013+ config .files .log .destination .c = validate_stub ;
2014+
2015+ // Read log file path: ENV > TOML > legacy
2016+ // ENV is always checked so it works during early init (try_read=false).
2017+ // When try_read is true, TOML and legacy are also checked. Since ENV
2018+ // runs last, it takes precedence over TOML and legacy if set.
2019+ if (try_read )
2020+ {
2021+ if (!getLogFilePathTOML ())
2022+ getLogFilePathLegacy (& config , NULL );
2023+ }
2024+ getLogFilePathENV ();
2025+
2026+ // Read log destination: ENV > TOML
2027+ // Same priority logic: ENV runs last and wins if set.
2028+ if (try_read )
2029+ getLogDestinationTOML ();
2030+ getLogDestinationENV ();
19852031
19862032 return true;
19872033}
@@ -2033,6 +2079,7 @@ const char * __attribute__ ((const)) get_conf_type_str(const enum conf_type type
20332079 case CONF_ENUM_WEB_THEME :
20342080 case CONF_ENUM_TEMP_UNIT :
20352081 case CONF_ENUM_BLOCKING_EDNS_MODE :
2082+ case CONF_ENUM_LOG_DESTINATION :
20362083 return "enum (string)" ;
20372084 case CONF_ENUM_PRIVACY_LEVEL :
20382085 return "enum (unsigned integer)" ;
0 commit comments