@@ -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" ;
@@ -1978,6 +1981,20 @@ static bool getLogFilePathENV(void)
19781981 return true;
19791982}
19801983
1984+ static bool getLogDestinationENV (void )
1985+ {
1986+ const char * val = getenv (FTLCONF_PREFIX "files_log_destination" );
1987+ if (val == NULL || * val == '\0' )
1988+ return false;
1989+
1990+ const int dest = get_log_destination_val (val );
1991+ if (dest == -1 )
1992+ return false;
1993+
1994+ config .files .log .destination .v .log_destination = dest ;
1995+ return true;
1996+ }
1997+
19811998bool getLogFilePath (bool try_read )
19821999{
19832000 // Initialize memory
@@ -1993,9 +2010,38 @@ bool getLogFilePath(bool try_read)
19932010 config .files .log .ftl .c = validate_filepath ;
19942011 config .files .log .ftl .f = FLAG_FTL_LOG ;
19952012
1996- // Try sources in priority order: ENV > TOML > legacy
1997- if (try_read && !getLogFilePathENV () && !getLogFilePathTOML ())
1998- return getLogFilePathLegacy (& config , NULL );
2013+ // Initialize log destination
2014+ config .files .log .destination .k = "files.log.destination" ;
2015+ config .files .log .destination .h = "Where to write FTL, webserver and dnsmasq log output" ;
2016+ {
2017+ struct enum_options log_destination [] =
2018+ {
2019+ { "FILE" , "Write logs to the configured log files" },
2020+ { "JSON" , "Write logs as structured JSON to stdout" }
2021+ };
2022+ CONFIG_ADD_ENUM_OPTIONS (config .files .log .destination .a , log_destination );
2023+ }
2024+ config .files .log .destination .t = CONF_ENUM_LOG_DESTINATION ;
2025+ config .files .log .destination .f = FLAG_READ_ONLY ;
2026+ config .files .log .destination .d .log_destination = LOG_DEST_FILE ;
2027+ config .files .log .destination .c = validate_stub ;
2028+
2029+ // Read log file path: ENV > TOML > legacy
2030+ // ENV is always checked so it works during early init (try_read=false).
2031+ // When try_read is true, TOML and legacy are also checked. Since ENV
2032+ // runs last, it takes precedence over TOML and legacy if set.
2033+ if (try_read )
2034+ {
2035+ if (!getLogFilePathTOML ())
2036+ getLogFilePathLegacy (& config , NULL );
2037+ }
2038+ getLogFilePathENV ();
2039+
2040+ // Read log destination: ENV > TOML
2041+ // Same priority logic: ENV runs last and wins if set.
2042+ if (try_read )
2043+ getLogDestinationTOML ();
2044+ getLogDestinationENV ();
19992045
20002046 return true;
20012047}
@@ -2047,6 +2093,7 @@ const char * __attribute__ ((const)) get_conf_type_str(const enum conf_type type
20472093 case CONF_ENUM_WEB_THEME :
20482094 case CONF_ENUM_TEMP_UNIT :
20492095 case CONF_ENUM_BLOCKING_EDNS_MODE :
2096+ case CONF_ENUM_LOG_DESTINATION :
20502097 return "enum (string)" ;
20512098 case CONF_ENUM_PRIVACY_LEVEL :
20522099 return "enum (unsigned integer)" ;
0 commit comments