This is an automated email from the ASF dual-hosted git repository.
jiadongb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new e908c60de8 chore: make service log levels configurable via
TEXERA_SERVICE_LOG_LEVEL (#4244)
e908c60de8 is described below
commit e908c60de85ec42fa3be4d8e82c9fcc96e970d0b
Author: Jiadong Bai <[email protected]>
AuthorDate: Fri Feb 27 20:35:16 2026 -0800
chore: make service log levels configurable via TEXERA_SERVICE_LOG_LEVEL
(#4244)
### What changes were proposed in this PR?
This PR makes log levels configurable across all 7 Texera services via a
single `TEXERA_SERVICE_LOG_LEVEL` environment variable, defaulting to
`INFO`.
Changes include:
- Enable Dropwizard's `EnvironmentVariableSubstitutor` in each service's
`initialize()` to support `${VAR:-default}` syntax in YAML configs
- Replace all hardcoded `level: INFO` with `level:
${TEXERA_SERVICE_LOG_LEVEL:-INFO}` in Dropwizard YAML configs,
logback.xml files, and Pekko cluster.conf
- Disable Dropwizard's built-in `requestLog` console appender (which
uses a separate logback-access pipeline not controllable by standard log
levels) and replace it with a servlet filter that routes HTTP access
logs through SLF4J at INFO level
- Extract shared `RequestLoggingFilter` class in `common/auth` for the 4
DW 4.x services; DW 1.3.x services use inline filters with a TODO to
migrate after Dropwizard upgrade
- Add `TEXERA_SERVICE_LOG_LEVEL=INFO` to `bin/single-node/.env`
### Any related issues, documentation, discussions?
Closes #4243
### How was this PR tested?
- Manually set `TEXERA_SERVICE_LOG_LEVEL=ERROR` and verified only
error-level logs appear (no HTTP access logs, no INFO messages)
- Manually set `TEXERA_SERVICE_LOG_LEVEL=INFO` (or left unset) and
verified normal logging behavior including HTTP access logs
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 4.6)
---
.../access-control-service-web-config.yaml | 7 ++-
.../src/main/resources/logback.xml | 2 +-
.../texera/service/AccessControlService.scala | 14 ++++-
.../resources/computing-unit-master-config.yml | 8 +--
amber/src/main/resources/logback.xml | 2 +-
.../texera-compiling-service-web-config.yml | 5 +-
amber/src/main/resources/web-config.yml | 5 +-
.../apache/texera/web/ComputingUnitMaster.scala | 35 ++++++++++++
.../apache/texera/web/TexeraWebApplication.scala | 36 +++++++++++-
.../web/service/ExecutionResultService.scala | 3 +-
bin/single-node/.env | 3 +
common/auth/build.sbt | 4 +-
.../apache/texera/auth/RequestLoggingFilter.scala | 64 ++++++++++++++++++++++
common/config/src/main/resources/cluster.conf | 1 +
.../computing-unit-managing-service-config.yaml | 7 ++-
.../service/ComputingUnitManagingService.scala | 14 ++++-
.../main/resources/config-service-web-config.yaml | 7 ++-
.../org/apache/texera/service/ConfigService.scala | 13 ++++-
.../main/resources/file-service-web-config.yaml | 7 ++-
.../org/apache/texera/service/FileService.scala | 14 ++++-
.../workflow-compiling-service-config.yaml | 7 ++-
.../texera/service/WorkflowCompilingService.scala | 32 +++++++++++
22 files changed, 256 insertions(+), 34 deletions(-)
diff --git
a/access-control-service/src/main/resources/access-control-service-web-config.yaml
b/access-control-service/src/main/resources/access-control-service-web-config.yaml
index e8d17cec28..8c7895e985 100644
---
a/access-control-service/src/main/resources/access-control-service-web-config.yaml
+++
b/access-control-service/src/main/resources/access-control-service-web-config.yaml
@@ -20,12 +20,15 @@ server:
- type: http
port: 9096
adminConnectors: []
+ requestLog:
+ type: classic
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
- threshold: INFO
+ threshold: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
- type: file
currentLogFilename: logs/access-control-service.log
archive: true
diff --git a/access-control-service/src/main/resources/logback.xml
b/access-control-service/src/main/resources/logback.xml
index 6a5e4871b4..99794f1968 100644
--- a/access-control-service/src/main/resources/logback.xml
+++ b/access-control-service/src/main/resources/logback.xml
@@ -45,7 +45,7 @@
<appender-ref ref="FILE"/>
</appender>
- <root level="INFO">
+ <root level="${TEXERA_SERVICE_LOG_LEVEL:-INFO}">
<appender-ref ref="ASYNC"/>
<appender-ref ref="STDOUT"/>
</root>
diff --git
a/access-control-service/src/main/scala/org/apache/texera/service/AccessControlService.scala
b/access-control-service/src/main/scala/org/apache/texera/service/AccessControlService.scala
index 7fac58328d..0ab9f0fbfe 100644
---
a/access-control-service/src/main/scala/org/apache/texera/service/AccessControlService.scala
+++
b/access-control-service/src/main/scala/org/apache/texera/service/AccessControlService.scala
@@ -20,10 +20,11 @@ package org.apache.texera.service
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.typesafe.scalalogging.LazyLogging
import io.dropwizard.auth.AuthDynamicFeature
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.core.Application
import io.dropwizard.core.setup.{Bootstrap, Environment}
import org.apache.texera.amber.config.StorageConfig
-import org.apache.texera.auth.{JwtAuthFilter, SessionUser}
+import org.apache.texera.auth.{JwtAuthFilter, RequestLoggingFilter,
SessionUser}
import org.apache.texera.dao.SqlServer
import org.apache.texera.service.resource.{
AccessControlResource,
@@ -32,11 +33,17 @@ import org.apache.texera.service.resource.{
LiteLLMProxyResource
}
import org.eclipse.jetty.server.session.SessionHandler
-
import java.nio.file.Path
class AccessControlService extends
Application[AccessControlServiceConfiguration] with LazyLogging {
override def initialize(bootstrap:
Bootstrap[AccessControlServiceConfiguration]): Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// Register Scala module to Dropwizard default object mapper
bootstrap.getObjectMapper.registerModule(DefaultScalaModule)
@@ -69,6 +76,9 @@ class AccessControlService extends
Application[AccessControlServiceConfiguration
environment.jersey.register(
new
io.dropwizard.auth.AuthValueFactoryProvider.Binder(classOf[SessionUser])
)
+
+ // Route request logs through SLF4J, controlled by TEXERA_SERVICE_LOG_LEVEL
+ RequestLoggingFilter.register(environment.getApplicationContext)
}
}
object AccessControlService {
diff --git a/amber/src/main/resources/computing-unit-master-config.yml
b/amber/src/main/resources/computing-unit-master-config.yml
index 88253f7812..0dba594b8a 100644
--- a/amber/src/main/resources/computing-unit-master-config.yml
+++ b/amber/src/main/resources/computing-unit-master-config.yml
@@ -28,14 +28,12 @@ server:
requestLog:
type: classic
timeZone: UTC
- appenders:
- - type: console
- threshold: ERROR # Only log errors in console for simplicity
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "io.dropwizard": INFO
+ "io.dropwizard": ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
logFormat: "[%date{ISO8601}] [%level] [%logger] [%thread] - %msg %n"
diff --git a/amber/src/main/resources/logback.xml
b/amber/src/main/resources/logback.xml
index aff1ee485e..43afb5d44c 100644
--- a/amber/src/main/resources/logback.xml
+++ b/amber/src/main/resources/logback.xml
@@ -46,7 +46,7 @@
<appender-ref ref="FILE"/>
</appender>
- <root level="INFO">
+ <root level="${TEXERA_SERVICE_LOG_LEVEL:-INFO}">
<appender-ref ref="ASYNC"/>
<appender-ref ref="STDOUT"/>
</root>
diff --git a/amber/src/main/resources/texera-compiling-service-web-config.yml
b/amber/src/main/resources/texera-compiling-service-web-config.yml
index 94a00fc453..ea2c1b9c1e 100644
--- a/amber/src/main/resources/texera-compiling-service-web-config.yml
+++ b/amber/src/main/resources/texera-compiling-service-web-config.yml
@@ -29,7 +29,6 @@ server:
type: classic
timeZone: UTC
appenders:
- - type: console
- type: file
currentLogFilename: logs/access.log
threshold: ALL
@@ -41,9 +40,9 @@ server:
bufferSize: 8KiB
immediateFlush: true
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "io.dropwizard": INFO
+ "io.dropwizard": ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
logFormat: "[%date{ISO8601}] [%level] [%logger] [%thread] - %msg %n"
diff --git a/amber/src/main/resources/web-config.yml
b/amber/src/main/resources/web-config.yml
index c777cecd85..9fde1d078e 100644
--- a/amber/src/main/resources/web-config.yml
+++ b/amber/src/main/resources/web-config.yml
@@ -29,7 +29,6 @@ server:
type: classic
timeZone: UTC
appenders:
- - type: console
- type: file
currentLogFilename: logs/access.log
threshold: ALL
@@ -41,9 +40,9 @@ server:
bufferSize: 8KiB
immediateFlush: true
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "io.dropwizard": INFO
+ "io.dropwizard": ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
logFormat: "[%date{ISO8601}] [%level] [%logger] [%thread] - %msg %n"
diff --git
a/amber/src/main/scala/org/apache/texera/web/ComputingUnitMaster.scala
b/amber/src/main/scala/org/apache/texera/web/ComputingUnitMaster.scala
index 225f5c152a..4b07113b1c 100644
--- a/amber/src/main/scala/org/apache/texera/web/ComputingUnitMaster.scala
+++ b/amber/src/main/scala/org/apache/texera/web/ComputingUnitMaster.scala
@@ -22,6 +22,7 @@ package org.apache.texera.web
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.typesafe.scalalogging.LazyLogging
import io.dropwizard.Configuration
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.setup.{Bootstrap, Environment}
import io.dropwizard.websockets.WebsocketBundle
import org.apache.texera.amber.config.{ApplicationConfig, StorageConfig}
@@ -49,6 +50,7 @@ import
org.apache.texera.web.resource.dashboard.user.workflow.WorkflowExecutions
import org.apache.texera.web.resource.{WebsocketPayloadSizeTuner,
WorkflowWebsocketResource}
import org.apache.texera.web.service.ExecutionsMetadataPersistService
import org.eclipse.jetty.server.session.SessionHandler
+import org.eclipse.jetty.servlet.FilterHolder
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter
import java.net.URI
@@ -112,6 +114,13 @@ object ComputingUnitMaster {
class ComputingUnitMaster extends io.dropwizard.Application[Configuration]
with LazyLogging {
override def initialize(bootstrap: Bootstrap[Configuration]): Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// add websocket bundle
bootstrap.addBundle(new
WebsocketBundle(classOf[WorkflowWebsocketResource]))
// register scala module to dropwizard default object mapper
@@ -180,6 +189,32 @@ class ComputingUnitMaster extends
io.dropwizard.Application[Configuration] with
}
environment.jersey.register(classOf[WorkflowExecutionsResource])
+
+ // Route request logs through SLF4J, controlled by
TEXERA_SERVICE_LOG_LEVEL.
+ // TODO: replace with RequestLoggingFilter.register() from common/auth
once Dropwizard is upgraded to 4.x
+ val requestLogger =
org.slf4j.LoggerFactory.getLogger("org.eclipse.jetty.server.RequestLog")
+ environment.getApplicationContext.addFilter(
+ new FilterHolder(new javax.servlet.Filter {
+ override def init(filterConfig: javax.servlet.FilterConfig): Unit = {}
+ override def doFilter(
+ request: javax.servlet.ServletRequest,
+ response: javax.servlet.ServletResponse,
+ chain: javax.servlet.FilterChain
+ ): Unit = {
+ chain.doFilter(request, response)
+ if (requestLogger.isInfoEnabled) {
+ val req =
request.asInstanceOf[javax.servlet.http.HttpServletRequest]
+ val resp =
response.asInstanceOf[javax.servlet.http.HttpServletResponse]
+ requestLogger.info(
+ s"""${req.getRemoteAddr} - "${req.getMethod}
${req.getRequestURI} ${req.getProtocol}" ${resp.getStatus}"""
+ )
+ }
+ }
+ override def destroy(): Unit = {}
+ }),
+ "/*",
+ java.util.EnumSet.allOf(classOf[javax.servlet.DispatcherType])
+ )
}
/**
diff --git
a/amber/src/main/scala/org/apache/texera/web/TexeraWebApplication.scala
b/amber/src/main/scala/org/apache/texera/web/TexeraWebApplication.scala
index 4264a9ca18..98b7c68c97 100644
--- a/amber/src/main/scala/org/apache/texera/web/TexeraWebApplication.scala
+++ b/amber/src/main/scala/org/apache/texera/web/TexeraWebApplication.scala
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.github.dirkraft.dropwizard.fileassets.FileAssetsBundle
import com.typesafe.scalalogging.LazyLogging
import io.dropwizard.auth.AuthValueFactoryProvider
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.setup.{Bootstrap, Environment}
import io.dropwizard.websockets.WebsocketBundle
import org.apache.texera.amber.config.StorageConfig
@@ -52,7 +53,7 @@ import
org.apache.texera.web.resource.dashboard.user.workflow.{
WorkflowVersionResource
}
import org.eclipse.jetty.server.session.SessionHandler
-import org.eclipse.jetty.servlet.ErrorPageErrorHandler
+import org.eclipse.jetty.servlet.{ErrorPageErrorHandler, FilterHolder}
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature
@@ -84,6 +85,13 @@ class TexeraWebApplication
with LazyLogging {
override def initialize(bootstrap: Bootstrap[TexeraWebConfiguration]): Unit
= {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// serve static frontend GUI files
bootstrap.addBundle(new FileAssetsBundle("../../frontend/dist", "/",
"index.html"))
// add websocket bundle
@@ -154,5 +162,31 @@ class TexeraWebApplication
environment.jersey.register(classOf[AIAssistantResource])
AuthResource.createAdminUser()
+
+ // Route request logs through SLF4J, controlled by
TEXERA_SERVICE_LOG_LEVEL.
+ // TODO: replace with RequestLoggingFilter.register() from common/auth
once Dropwizard is upgraded to 4.x
+ val requestLogger =
org.slf4j.LoggerFactory.getLogger("org.eclipse.jetty.server.RequestLog")
+ environment.getApplicationContext.addFilter(
+ new FilterHolder(new javax.servlet.Filter {
+ override def init(filterConfig: javax.servlet.FilterConfig): Unit = {}
+ override def doFilter(
+ request: javax.servlet.ServletRequest,
+ response: javax.servlet.ServletResponse,
+ chain: javax.servlet.FilterChain
+ ): Unit = {
+ chain.doFilter(request, response)
+ if (requestLogger.isInfoEnabled) {
+ val req =
request.asInstanceOf[javax.servlet.http.HttpServletRequest]
+ val resp =
response.asInstanceOf[javax.servlet.http.HttpServletResponse]
+ requestLogger.info(
+ s"""${req.getRemoteAddr} - "${req.getMethod}
${req.getRequestURI} ${req.getProtocol}" ${resp.getStatus}"""
+ )
+ }
+ }
+ override def destroy(): Unit = {}
+ }),
+ "/*",
+ java.util.EnumSet.allOf(classOf[javax.servlet.DispatcherType])
+ )
}
}
diff --git
a/amber/src/main/scala/org/apache/texera/web/service/ExecutionResultService.scala
b/amber/src/main/scala/org/apache/texera/web/service/ExecutionResultService.scala
index 285c836b60..3f0362f824 100644
---
a/amber/src/main/scala/org/apache/texera/web/service/ExecutionResultService.scala
+++
b/amber/src/main/scala/org/apache/texera/web/service/ExecutionResultService.scala
@@ -23,8 +23,7 @@ import org.apache.pekko.actor.Cancellable
import com.fasterxml.jackson.annotation.{JsonTypeInfo, JsonTypeName}
import com.fasterxml.jackson.databind.node.ObjectNode
import com.typesafe.scalalogging.LazyLogging
-import org.apache.texera.amber.config.{ApplicationConfig, StorageConfig}
-import org.apache.texera.amber.core.storage.DocumentFactory.ICEBERG
+import org.apache.texera.amber.config.ApplicationConfig
import org.apache.texera.amber.core.storage.model.VirtualDocument
import org.apache.texera.amber.core.storage.result._
import org.apache.texera.amber.core.storage.{DocumentFactory, VFSURIFactory}
diff --git a/bin/single-node/.env b/bin/single-node/.env
index 0b9c4916af..4da884bab0 100644
--- a/bin/single-node/.env
+++ b/bin/single-node/.env
@@ -17,6 +17,9 @@
TEXERA_HOST=http://localhost
+# Log level for all Texera services (valid values: ERROR, WARN, INFO, DEBUG)
+TEXERA_SERVICE_LOG_LEVEL=INFO
+
# Container image configuration
# Override these to use a different registry or image version
IMAGE_REGISTRY=ghcr.io/apache
diff --git a/common/auth/build.sbt b/common/auth/build.sbt
index a89812d80c..3d2b3685c1 100644
--- a/common/auth/build.sbt
+++ b/common/auth/build.sbt
@@ -59,5 +59,7 @@ libraryDependencies ++= Seq(
"com.typesafe" % "config" % "1.4.3", //
config reader
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5", // for
LazyLogging
"org.bitbucket.b_c" % "jose4j" % "0.9.6", // for
jwt parser
- "jakarta.ws.rs" % "jakarta.ws.rs-api" % "3.0.0" // for
JwtAuthFilter
+ "jakarta.ws.rs" % "jakarta.ws.rs-api" % "3.0.0", // for
JwtAuthFilter
+ "jakarta.servlet" % "jakarta.servlet-api" % "5.0.0" % "provided", // for
RequestLoggingFilter
+ "org.eclipse.jetty" % "jetty-servlet" % "11.0.24" % "provided" // for
FilterHolder
)
\ No newline at end of file
diff --git
a/common/auth/src/main/scala/org/apache/texera/auth/RequestLoggingFilter.scala
b/common/auth/src/main/scala/org/apache/texera/auth/RequestLoggingFilter.scala
new file mode 100644
index 0000000000..9a1587d0f1
--- /dev/null
+++
b/common/auth/src/main/scala/org/apache/texera/auth/RequestLoggingFilter.scala
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.texera.auth
+
+import jakarta.servlet._
+import jakarta.servlet.http.{HttpServletRequest, HttpServletResponse}
+import org.slf4j.LoggerFactory
+
+/**
+ * Servlet filter that logs HTTP requests through SLF4J at INFO level.
+ * This replaces Dropwizard's built-in request log (which uses a separate
+ * access log pipeline not controllable by log level) so that request logs
+ * are fully controlled by the TEXERA_SERVICE_LOG_LEVEL environment variable.
+ */
+class RequestLoggingFilter extends Filter {
+ private val logger =
LoggerFactory.getLogger("org.eclipse.jetty.server.RequestLog")
+
+ override def doFilter(
+ request: ServletRequest,
+ response: ServletResponse,
+ chain: FilterChain
+ ): Unit = {
+ chain.doFilter(request, response)
+ if (logger.isInfoEnabled) {
+ val req = request.asInstanceOf[HttpServletRequest]
+ val resp = response.asInstanceOf[HttpServletResponse]
+ logger.info(
+ s"""${req.getRemoteAddr} - "${req.getMethod} ${req.getRequestURI}
${req.getProtocol}" ${resp.getStatus}"""
+ )
+ }
+ }
+}
+
+object RequestLoggingFilter {
+
+ /**
+ * Registers the request logging filter on the given servlet context.
+ * Usage: RequestLoggingFilter.register(environment.getApplicationContext)
+ */
+ def register(context: org.eclipse.jetty.servlet.ServletContextHandler): Unit
= {
+ context.addFilter(
+ new org.eclipse.jetty.servlet.FilterHolder(new RequestLoggingFilter),
+ "/*",
+ java.util.EnumSet.allOf(classOf[DispatcherType])
+ )
+ }
+}
diff --git a/common/config/src/main/resources/cluster.conf
b/common/config/src/main/resources/cluster.conf
index adf42fccde..524cd0216d 100644
--- a/common/config/src/main/resources/cluster.conf
+++ b/common/config/src/main/resources/cluster.conf
@@ -24,6 +24,7 @@ pekko {
# as they have been started; before that, see "stdout-loglevel"
# Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = "INFO"
+ loglevel = ${?TEXERA_SERVICE_LOG_LEVEL}
# Log level for the very basic logger activated during ActorSystem startup.
# This logger prints the log messages to stdout (System.out).
diff --git
a/computing-unit-managing-service/src/main/resources/computing-unit-managing-service-config.yaml
b/computing-unit-managing-service/src/main/resources/computing-unit-managing-service-config.yaml
index ed1cb62e6c..523b419798 100644
---
a/computing-unit-managing-service/src/main/resources/computing-unit-managing-service-config.yaml
+++
b/computing-unit-managing-service/src/main/resources/computing-unit-managing-service-config.yaml
@@ -23,8 +23,11 @@ server:
adminConnectors:
- type: http
port: 8082
+ requestLog:
+ type: classic
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "com.example": DEBUG
\ No newline at end of file
+ "com.example": ${TEXERA_SERVICE_LOG_LEVEL:-DEBUG}
\ No newline at end of file
diff --git
a/computing-unit-managing-service/src/main/scala/org/apache/texera/service/ComputingUnitManagingService.scala
b/computing-unit-managing-service/src/main/scala/org/apache/texera/service/ComputingUnitManagingService.scala
index 1c0cf8768d..a15ced30a2 100644
---
a/computing-unit-managing-service/src/main/scala/org/apache/texera/service/ComputingUnitManagingService.scala
+++
b/computing-unit-managing-service/src/main/scala/org/apache/texera/service/ComputingUnitManagingService.scala
@@ -21,17 +21,17 @@ package org.apache.texera.service
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import io.dropwizard.auth.AuthDynamicFeature
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.core.Application
import io.dropwizard.core.setup.{Bootstrap, Environment}
import org.apache.texera.amber.config.StorageConfig
-import org.apache.texera.auth.{JwtAuthFilter, SessionUser}
+import org.apache.texera.auth.{JwtAuthFilter, RequestLoggingFilter,
SessionUser}
import org.apache.texera.dao.SqlServer
import org.apache.texera.service.resource.{
ComputingUnitAccessResource,
ComputingUnitManagingResource,
HealthCheckResource
}
-
import java.nio.file.Path
class ComputingUnitManagingService extends
Application[ComputingUnitManagingServiceConfiguration] {
@@ -39,6 +39,13 @@ class ComputingUnitManagingService extends
Application[ComputingUnitManagingServ
override def initialize(
bootstrap: Bootstrap[ComputingUnitManagingServiceConfiguration]
): Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// register scala module to dropwizard default object mapper
bootstrap.getObjectMapper.registerModule(DefaultScalaModule)
}
@@ -65,6 +72,9 @@ class ComputingUnitManagingService extends
Application[ComputingUnitManagingServ
environment.jersey().register(new ComputingUnitManagingResource)
environment.jersey().register(new ComputingUnitAccessResource)
+
+ // Route request logs through SLF4J, controlled by TEXERA_SERVICE_LOG_LEVEL
+ RequestLoggingFilter.register(environment.getApplicationContext)
}
}
diff --git a/config-service/src/main/resources/config-service-web-config.yaml
b/config-service/src/main/resources/config-service-web-config.yaml
index 45a1ff8dd1..4aa67af82e 100644
--- a/config-service/src/main/resources/config-service-web-config.yaml
+++ b/config-service/src/main/resources/config-service-web-config.yaml
@@ -20,12 +20,15 @@ server:
- type: http
port: 9094
adminConnectors: []
+ requestLog:
+ type: classic
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
- threshold: INFO
+ threshold: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
- type: file
currentLogFilename: logs/config-service.log
archive: true
diff --git
a/config-service/src/main/scala/org/apache/texera/service/ConfigService.scala
b/config-service/src/main/scala/org/apache/texera/service/ConfigService.scala
index c226eaf9c4..c787016c27 100644
---
a/config-service/src/main/scala/org/apache/texera/service/ConfigService.scala
+++
b/config-service/src/main/scala/org/apache/texera/service/ConfigService.scala
@@ -22,10 +22,11 @@ package org.apache.texera.service
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.typesafe.scalalogging.LazyLogging
import io.dropwizard.auth.AuthDynamicFeature
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.core.Application
import io.dropwizard.core.setup.{Bootstrap, Environment}
import org.apache.texera.amber.config.StorageConfig
-import org.apache.texera.auth.{JwtAuthFilter, SessionUser}
+import org.apache.texera.auth.{JwtAuthFilter, RequestLoggingFilter,
SessionUser}
import org.apache.texera.config.DefaultsConfig
import org.apache.texera.dao.SqlServer
import org.apache.texera.service.resource.{ConfigResource, HealthCheckResource}
@@ -36,6 +37,13 @@ import java.nio.file.Path
class ConfigService extends Application[ConfigServiceConfiguration] with
LazyLogging {
override def initialize(bootstrap: Bootstrap[ConfigServiceConfiguration]):
Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// Register Scala module to Dropwizard default object mapper
bootstrap.getObjectMapper.registerModule(DefaultScalaModule)
@@ -94,6 +102,9 @@ class ConfigService extends
Application[ConfigServiceConfiguration] with LazyLog
logger.error("Failed to preload default settings", ex)
throw ex
}
+
+ // Route request logs through SLF4J, controlled by TEXERA_SERVICE_LOG_LEVEL
+ RequestLoggingFilter.register(environment.getApplicationContext)
}
}
diff --git a/file-service/src/main/resources/file-service-web-config.yaml
b/file-service/src/main/resources/file-service-web-config.yaml
index e9c0e33c05..41f8d1b174 100644
--- a/file-service/src/main/resources/file-service-web-config.yaml
+++ b/file-service/src/main/resources/file-service-web-config.yaml
@@ -20,11 +20,14 @@ server:
- type: http
port: 9092
adminConnectors: []
+ requestLog:
+ type: classic
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "io.dropwizard": INFO
+ "io.dropwizard": ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
- type: file
diff --git
a/file-service/src/main/scala/org/apache/texera/service/FileService.scala
b/file-service/src/main/scala/org/apache/texera/service/FileService.scala
index a92eaca511..20bb242bc1 100644
--- a/file-service/src/main/scala/org/apache/texera/service/FileService.scala
+++ b/file-service/src/main/scala/org/apache/texera/service/FileService.scala
@@ -23,11 +23,12 @@ import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.typesafe.scalalogging.LazyLogging
import io.dropwizard.auth.AuthDynamicFeature
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.core.Application
import io.dropwizard.core.setup.{Bootstrap, Environment}
import org.apache.texera.amber.config.StorageConfig
import org.apache.texera.amber.core.storage.util.LakeFSStorageClient
-import org.apache.texera.auth.{JwtAuthFilter, SessionUser}
+import org.apache.texera.auth.{JwtAuthFilter, RequestLoggingFilter,
SessionUser}
import org.apache.texera.dao.SqlServer
import org.apache.texera.service.`type`.DatasetFileNode
import org.apache.texera.service.`type`.serde.DatasetFileNodeSerializer
@@ -38,11 +39,17 @@ import org.apache.texera.service.resource.{
}
import org.apache.texera.service.util.S3StorageClient
import org.eclipse.jetty.server.session.SessionHandler
-
import java.nio.file.Path
class FileService extends Application[FileServiceConfiguration] with
LazyLogging {
override def initialize(bootstrap: Bootstrap[FileServiceConfiguration]):
Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// Register Scala module to Dropwizard default object mapper
bootstrap.getObjectMapper.registerModule(DefaultScalaModule)
@@ -81,6 +88,9 @@ class FileService extends
Application[FileServiceConfiguration] with LazyLogging
environment.jersey.register(classOf[DatasetResource])
environment.jersey.register(classOf[DatasetAccessResource])
+
+ // Route request logs through SLF4J, controlled by TEXERA_SERVICE_LOG_LEVEL
+ RequestLoggingFilter.register(environment.getApplicationContext)
}
}
diff --git
a/workflow-compiling-service/src/main/resources/workflow-compiling-service-config.yaml
b/workflow-compiling-service/src/main/resources/workflow-compiling-service-config.yaml
index 6ad15eaeb2..5b9016af1b 100644
---
a/workflow-compiling-service/src/main/resources/workflow-compiling-service-config.yaml
+++
b/workflow-compiling-service/src/main/resources/workflow-compiling-service-config.yaml
@@ -20,11 +20,14 @@ server:
- type: http
port: 9090
adminConnectors: []
+ requestLog:
+ type: classic
+ appenders: []
logging:
- level: INFO
+ level: ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
loggers:
- "io.dropwizard": INFO
+ "io.dropwizard": ${TEXERA_SERVICE_LOG_LEVEL:-INFO}
appenders:
- type: console
- type: file
diff --git
a/workflow-compiling-service/src/main/scala/org/apache/texera/service/WorkflowCompilingService.scala
b/workflow-compiling-service/src/main/scala/org/apache/texera/service/WorkflowCompilingService.scala
index 27aad902fe..40fb3a2dd8 100644
---
a/workflow-compiling-service/src/main/scala/org/apache/texera/service/WorkflowCompilingService.scala
+++
b/workflow-compiling-service/src/main/scala/org/apache/texera/service/WorkflowCompilingService.scala
@@ -20,17 +20,26 @@
package org.apache.texera.service
import com.fasterxml.jackson.module.scala.DefaultScalaModule
+import io.dropwizard.configuration.{EnvironmentVariableSubstitutor,
SubstitutingSourceProvider}
import io.dropwizard.core.Application
import io.dropwizard.core.setup.{Bootstrap, Environment}
import org.apache.texera.amber.config.StorageConfig
import org.apache.texera.amber.util.ObjectMapperUtils
import org.apache.texera.dao.SqlServer
import org.apache.texera.service.resource.{HealthCheckResource,
WorkflowCompilationResource}
+import org.eclipse.jetty.servlet.FilterHolder
import java.nio.file.Path
class WorkflowCompilingService extends
Application[WorkflowCompilingServiceConfiguration] {
override def initialize(bootstrap:
Bootstrap[WorkflowCompilingServiceConfiguration]): Unit = {
+ // enable environment variable substitution in YAML config
+ bootstrap.setConfigurationSourceProvider(
+ new SubstitutingSourceProvider(
+ bootstrap.getConfigurationSourceProvider,
+ new EnvironmentVariableSubstitutor(false)
+ )
+ )
// register scala module to dropwizard default object mapper
bootstrap.getObjectMapper.registerModule(DefaultScalaModule)
}
@@ -54,6 +63,29 @@ class WorkflowCompilingService extends
Application[WorkflowCompilingServiceConfi
// register the compilation endpoint
environment.jersey.register(classOf[WorkflowCompilationResource])
+
+ // Route request logs through SLF4J, controlled by TEXERA_SERVICE_LOG_LEVEL
+ val requestLogger =
org.slf4j.LoggerFactory.getLogger("org.eclipse.jetty.server.RequestLog")
+ environment.getApplicationContext.addFilter(
+ new FilterHolder(new jakarta.servlet.Filter {
+ override def doFilter(
+ request: jakarta.servlet.ServletRequest,
+ response: jakarta.servlet.ServletResponse,
+ chain: jakarta.servlet.FilterChain
+ ): Unit = {
+ chain.doFilter(request, response)
+ if (requestLogger.isInfoEnabled) {
+ val req =
request.asInstanceOf[jakarta.servlet.http.HttpServletRequest]
+ val resp =
response.asInstanceOf[jakarta.servlet.http.HttpServletResponse]
+ requestLogger.info(
+ s"""${req.getRemoteAddr} - "${req.getMethod}
${req.getRequestURI} ${req.getProtocol}" ${resp.getStatus}"""
+ )
+ }
+ }
+ }),
+ "/*",
+ java.util.EnumSet.allOf(classOf[jakarta.servlet.DispatcherType])
+ )
}
}