Repository: asterixdb
Updated Branches:
  refs/heads/master 7887e352b -> 31fb2e79f


[ASTERIXDB-2017][API] Access logs, log rotation

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- Common Log Format (httpd) style logs for each servlet access.
- Log rotation by default in asterix-server package, rather than
  console logging with no rotation

Change-Id: I9a8d76bec308b2fdb20c33370fc9e58a154ba968
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1915
Reviewed-by: Michael Blow <mb...@apache.org>
Sonar-Qube: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/31fb2e79
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/31fb2e79
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/31fb2e79

Branch: refs/heads/master
Commit: 31fb2e79fc00350cd2e60fc11ce87e3e1fa98617
Parents: 7887e35
Author: Ian Maxon <ima...@apache.org>
Authored: Mon Aug 13 18:43:21 2018 -0700
Committer: Michael Blow <mb...@apache.org>
Committed: Mon Aug 13 23:32:40 2018 -0700

----------------------------------------------------------------------
 .../asterix-app/src/main/resources/cc.conf      |   1 +
 .../asterix-app/src/main/resources/cc2.conf     |   1 +
 .../asterix-app/src/main/resources/cc3.conf     |   1 +
 .../asterix-app/src/main/resources/cc4.conf     |   1 +
 .../asterix-app/src/main/resources/log4j2.xml   |   9 ++
 .../asterix-app/src/test/resources/cc.conf      |   1 +
 .../cluster_state_1/cluster_state_1.1.regexadm  |   1 +
 .../cluster_state_1_full.1.regexadm             |   1 +
 .../cluster_state_1_less.1.regexadm             |   1 +
 .../src/main/opt/local/conf/cc.conf             |   3 +-
 .../hyracks-control/hyracks-control-cc/pom.xml  |   4 +
 .../org/apache/hyracks/control/cc/CCDriver.java |  10 ++
 .../control/cc/CCLogConfigurationFactory.java   |  89 ++++++++++++
 .../common/controllers/ControllerConfig.java    |  26 +++-
 .../hyracks-control/hyracks-control-nc/pom.xml  |   4 +
 .../org/apache/hyracks/control/nc/NCDriver.java |  10 ++
 .../control/nc/NCLogConfigurationFactory.java   |  95 +++++++++++++
 .../apache/hyracks/http/server/CLFLogger.java   | 135 +++++++++++++++++++
 .../apache/hyracks/http/server/HttpServer.java  |  15 ++-
 .../http/server/HttpServerInitializer.java      |   4 +
 20 files changed, 404 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/main/resources/cc.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/cc.conf 
b/asterixdb/asterix-app/src/main/resources/cc.conf
index 0d9f54f..6971b2b 100644
--- a/asterixdb/asterix-app/src/main/resources/cc.conf
+++ b/asterixdb/asterix-app/src/main/resources/cc.conf
@@ -46,6 +46,7 @@ heartbeat.period=2000
 heartbeat.max.misses=25
 
 [common]
+log.dir = logs/
 log.level = INFO
 compiler.framesize=32KB
 compiler.sortmemory=320KB

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/main/resources/cc2.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/cc2.conf 
b/asterixdb/asterix-app/src/main/resources/cc2.conf
index ddf1438..65dbafc 100644
--- a/asterixdb/asterix-app/src/main/resources/cc2.conf
+++ b/asterixdb/asterix-app/src/main/resources/cc2.conf
@@ -46,6 +46,7 @@ heartbeat.period=2000
 heartbeat.max.misses=25
 
 [common]
+log.dir = logs/
 log.level = WARN
 compiler.framesize=32KB
 compiler.sortmemory=320KB

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/main/resources/cc3.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/cc3.conf 
b/asterixdb/asterix-app/src/main/resources/cc3.conf
index b819f24..20aa70d 100644
--- a/asterixdb/asterix-app/src/main/resources/cc3.conf
+++ b/asterixdb/asterix-app/src/main/resources/cc3.conf
@@ -46,6 +46,7 @@ heartbeat.period=2000
 heartbeat.max.misses=25
 
 [common]
+log.dir = logs/
 log.level = WARN
 compiler.framesize=32KB
 compiler.sortmemory=320KB

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/main/resources/cc4.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/cc4.conf 
b/asterixdb/asterix-app/src/main/resources/cc4.conf
index 3b7a993..5bdf8ea 100644
--- a/asterixdb/asterix-app/src/main/resources/cc4.conf
+++ b/asterixdb/asterix-app/src/main/resources/cc4.conf
@@ -44,6 +44,7 @@ heartbeat.period=2000
 heartbeat.max.misses=25
 
 [common]
+log.dir = logs/
 log.level = INFO
 compiler.framesize=32KB
 compiler.sortmemory=320KB

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/main/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/log4j2.xml 
b/asterixdb/asterix-app/src/main/resources/log4j2.xml
index 1debf82..2ea8d4a 100644
--- a/asterixdb/asterix-app/src/main/resources/log4j2.xml
+++ b/asterixdb/asterix-app/src/main/resources/log4j2.xml
@@ -17,15 +17,24 @@
  ! under the License.
  !-->
 <Configuration status="WARN">
+   <CustomLevels>
+    <CustomLevel name="ACCESS" intLevel="550" />
+  </CustomLevels>
   <Appenders>
     <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - 
%msg%n"/>
     </Console>
+    <Console name="AccessLog" target="SYSTEM_OUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
   </Appenders>
   <Loggers>
     <Root level="WARN">
       <AppenderRef ref="Console"/>
     </Root>
     <Logger name="org.apache.hyracks.control.nc.service" level="INFO"/>
+    <Logger name="org.apache.hyracks.http.server.CLFLogger" level="ACCESS" 
additivity="false">
+        <AppenderRef ref="AccessLog"/>
+    </Logger>
   </Loggers>
 </Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/test/resources/cc.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/test/resources/cc.conf 
b/asterixdb/asterix-app/src/test/resources/cc.conf
index fc95dd4..2694408 100644
--- a/asterixdb/asterix-app/src/test/resources/cc.conf
+++ b/asterixdb/asterix-app/src/test/resources/cc.conf
@@ -46,6 +46,7 @@ heartbeat.period=2000
 heartbeat.max.misses=25
 
 [common]
+log.dir = logs/
 log.level = INFO
 compiler.framesize=32KB
 compiler.sortmemory=320KB

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
index ccb8c45..79db9ae 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1/cluster_state_1.1.regexadm
@@ -15,6 +15,7 @@
     "compiler\.sortmemory" : 327680,
     "compiler\.textsearchmemory" : 163840,
     "default\.dir" : "target/io/dir/asterixdb",
+    "log\.dir" : "logs/",
     "log\.level" : "INFO",
     "max\.wait\.active\.cluster" : 60,
     "max.web.request.size" : 52428800,

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
index 56fdf91..6e5547d 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_full/cluster_state_1_full.1.regexadm
@@ -15,6 +15,7 @@
     "compiler\.sortmemory" : 327680,
     "compiler\.textsearchmemory" : 163840,
     "default\.dir" : "target/io/dir/asterixdb",
+    "log\.dir" : "logs/",
     "log\.level" : "WARN",
     "max\.wait\.active\.cluster" : 60,
     "max.web.request.size" : 52428800,

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
index 658f4b1..3237551 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_1_less/cluster_state_1_less.1.regexadm
@@ -15,6 +15,7 @@
     "compiler\.sortmemory" : 327680,
     "compiler\.textsearchmemory" : 163840,
     "default\.dir" : "target/io/dir/asterixdb",
+    "log\.dir" : "logs/",
     "log\.level" : "WARN",
     "max\.wait\.active\.cluster" : 60,
     "max.web.request.size" : 52428800,

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/asterixdb/asterix-server/src/main/opt/local/conf/cc.conf
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-server/src/main/opt/local/conf/cc.conf 
b/asterixdb/asterix-server/src/main/opt/local/conf/cc.conf
index 6fc0579..bd5f403 100644
--- a/asterixdb/asterix-server/src/main/opt/local/conf/cc.conf
+++ b/asterixdb/asterix-server/src/main/opt/local/conf/cc.conf
@@ -37,4 +37,5 @@ command=${NC_COMMAND}
 address = 127.0.0.1
 
 [common]
-log.level=INFO
+log.dir = logs/
+log.level = INFO

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
index 6862582..86d6201 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
@@ -97,5 +97,9 @@
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
     </dependency>
+      <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
   </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCDriver.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCDriver.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCDriver.java
index a188594..c4ad139 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCDriver.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCDriver.java
@@ -30,6 +30,10 @@ import 
org.apache.hyracks.control.common.controllers.CCConfig;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.kohsuke.args4j.CmdLineException;
 
 public class CCDriver {
@@ -44,6 +48,12 @@ public class CCDriver {
             ICCApplication application = getApplication(args);
             application.registerConfig(configManager);
             CCConfig ccConfig = new CCConfig(configManager);
+            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+            Configuration cfg = ctx.getConfiguration();
+            CCLogConfigurationFactory logCfgFactory = new 
CCLogConfigurationFactory(ccConfig);
+            ConfigurationFactory.setConfigurationFactory(logCfgFactory);
+            cfg.removeLogger("Console");
+            ctx.start(logCfgFactory.getConfiguration(ctx, 
ConfigurationSource.NULL_SOURCE));
             ClusterControllerService ccService = new 
ClusterControllerService(ccConfig, application);
             ccService.start();
             while (true) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCLogConfigurationFactory.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCLogConfigurationFactory.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCLogConfigurationFactory.java
new file mode 100644
index 0000000..59ef913
--- /dev/null
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/CCLogConfigurationFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hyracks.control.cc;
+
+import org.apache.hyracks.control.common.controllers.CCConfig;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import 
org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+
+import java.net.URI;
+
+public class CCLogConfigurationFactory extends ConfigurationFactory {
+    private CCConfig config;
+
+    public CCLogConfigurationFactory(CCConfig config) {
+        this.config = config;
+    }
+
+    public Configuration 
createConfiguration(ConfigurationBuilder<BuiltConfiguration> builder) {
+        String logDir = config.getLogDir();
+        builder.setStatusLevel(Level.WARN);
+        builder.setConfigurationName("RollingBuilder");
+        // create a rolling file appender
+        LayoutComponentBuilder defaultLayout = 
builder.newLayout("PatternLayout").addAttribute("pattern",
+                "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n");
+        ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
+                
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule",
 "0 0 0 * * ?"))
+                
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size",
 "50M"));
+        AppenderComponentBuilder defaultRoll =
+                builder.newAppender("default", 
"RollingFile").addAttribute("fileName", logDir + "cc.log")
+                        .addAttribute("filePattern", logDir + 
"cc-%d{MM-dd-yy}.log.gz").add(defaultLayout)
+                        .addComponent(triggeringPolicy);
+        builder.add(defaultRoll);
+
+        // create the new logger
+        
builder.add(builder.newRootLogger(Level.INFO).add(builder.newAppenderRef("default")));
+
+        LayoutComponentBuilder accessLayout = 
builder.newLayout("PatternLayout").addAttribute("pattern", "%m%n");
+        AppenderComponentBuilder accessRoll =
+                builder.newAppender("access", 
"RollingFile").addAttribute("fileName", logDir + "access.log")
+                        .addAttribute("filePattern", logDir + 
"access-%d{MM-dd-yy}.log.gz").add(accessLayout)
+                        .addComponent(triggeringPolicy);
+        builder.add(accessRoll);
+        
builder.add(builder.newLogger("org.apache.hyracks.http.server.CLFLogger", 
Level.forName("ACCESS", 550))
+                
.add(builder.newAppenderRef("access")).addAttribute("additivity", false));
+
+        return builder.build();
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, 
final ConfigurationSource source) {
+        return getConfiguration(loggerContext, source.toString(), null);
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, 
final String name,
+            final URI configLocation) {
+        ConfigurationBuilder<BuiltConfiguration> builder = 
newConfigurationBuilder();
+        return createConfiguration(builder);
+    }
+
+    @Override
+    protected String[] getSupportedTypes() {
+        return new String[] { "*" };
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/ControllerConfig.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/ControllerConfig.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/ControllerConfig.java
index 8ecd312..65c7ca5 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/ControllerConfig.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/ControllerConfig.java
@@ -20,6 +20,7 @@ package org.apache.hyracks.control.common.controllers;
 
 import java.io.Serializable;
 import java.net.URL;
+import java.util.function.Function;
 
 import org.apache.hyracks.api.config.IApplicationConfig;
 import org.apache.hyracks.api.config.IOption;
@@ -35,21 +36,32 @@ public class ControllerConfig implements Serializable {
     private static final long serialVersionUID = 1L;
 
     public enum Option implements IOption {
-        CONFIG_FILE(OptionTypes.STRING, "Specify path to master configuration 
file", null),
-        CONFIG_FILE_URL(OptionTypes.URL, "Specify URL to master configuration 
file", null),
+        CONFIG_FILE(OptionTypes.STRING, (String) null, "Specify path to master 
configuration file"),
+        CONFIG_FILE_URL(OptionTypes.URL, (URL) null, "Specify URL to master 
configuration file"),
         DEFAULT_DIR(
                 OptionTypes.STRING,
                 "Directory where files are written to by default",
-                
FileUtil.joinPath(System.getProperty(ConfigurationUtil.JAVA_IO_TMPDIR), 
"hyracks")),;
+                
FileUtil.joinPath(System.getProperty(ConfigurationUtil.JAVA_IO_TMPDIR), 
"hyracks")),
+        LOG_DIR(
+                OptionTypes.STRING,
+                (Function<IApplicationConfig, String>) appConfig -> FileUtil
+                        
.joinPath(appConfig.getString(ControllerConfig.Option.DEFAULT_DIR), "logs/"),
+                "The directory where logs for this node are written");
 
         private final IOptionType type;
         private final String description;
-        private String defaultValue;
+        private Object defaultValue;
 
-        Option(IOptionType type, String description, String defaultValue) {
+        <T> Option(IOptionType<T> type, T defaultValue, String description) {
             this.type = type;
+            this.defaultValue = defaultValue;
             this.description = description;
+        }
+
+        <T> Option(IOptionType<T> type, Function<IApplicationConfig, T> 
defaultValue, String description) {
+            this.type = type;
             this.defaultValue = defaultValue;
+            this.description = description;
         }
 
         @Override
@@ -106,4 +118,8 @@ public class ControllerConfig implements Serializable {
     public void setConfigFileUrl(URL configFileUrl) {
         configManager.set(ControllerConfig.Option.CONFIG_FILE_URL, 
configFileUrl);
     }
+
+    public String getLogDir() {
+        return 
configManager.getAppConfig().getString(ControllerConfig.Option.LOG_DIR);
+    }
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/pom.xml
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/pom.xml 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/pom.xml
index c962029..d99b5ff 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/pom.xml
@@ -88,6 +88,10 @@
       <artifactId>log4j-api</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+    </dependency>
+    <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCDriver.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCDriver.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCDriver.java
index a03e0ce..fdd271c 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCDriver.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCDriver.java
@@ -28,6 +28,10 @@ import 
org.apache.hyracks.control.common.controllers.NCConfig;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.kohsuke.args4j.CmdLineException;
 
 @SuppressWarnings("InfiniteLoopStatement")
@@ -44,6 +48,12 @@ public class NCDriver {
             INCApplication application = getApplication(args);
             application.registerConfig(configManager);
             NCConfig ncConfig = new NCConfig(nodeId, configManager);
+            LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+            Configuration cfg = ctx.getConfiguration();
+            NCLogConfigurationFactory logCfgFactory = new 
NCLogConfigurationFactory(ncConfig);
+            ConfigurationFactory.setConfigurationFactory(logCfgFactory);
+            cfg.removeLogger("Console");
+            ctx.start(logCfgFactory.getConfiguration(ctx, 
ConfigurationSource.NULL_SOURCE));
             final NodeControllerService ncService = new 
NodeControllerService(ncConfig, application);
             ncService.start();
             while (true) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCLogConfigurationFactory.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCLogConfigurationFactory.java
 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCLogConfigurationFactory.java
new file mode 100644
index 0000000..990d6c9
--- /dev/null
+++ 
b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/NCLogConfigurationFactory.java
@@ -0,0 +1,95 @@
+/*
+ * 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.hyracks.control.nc;
+
+import org.apache.hyracks.control.common.controllers.NCConfig;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import 
org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
+import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
+import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
+
+import java.net.URI;
+
+public class NCLogConfigurationFactory extends ConfigurationFactory {
+    private NCConfig config;
+
+    public NCLogConfigurationFactory(NCConfig config) {
+        this.config = config;
+    }
+
+    public Configuration 
createConfiguration(ConfigurationBuilder<BuiltConfiguration> builder) {
+        String nodeId = config.getNodeId();
+        String logDir = config.getLogDir();
+        builder.setStatusLevel(Level.WARN);
+        builder.setConfigurationName("RollingBuilder");
+        // create a rolling file appender
+        LayoutComponentBuilder defaultLayout = 
builder.newLayout("PatternLayout").addAttribute("pattern",
+                "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n");
+        ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
+                
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule",
 "0 0 0 * * ?"))
+                
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size",
 "50M"));
+        AppenderComponentBuilder defaultRoll =
+                builder.newAppender("default", 
"RollingFile").addAttribute("fileName", logDir + "nc-" + nodeId + ".log")
+                        .addAttribute("filePattern", logDir + "nc-" + nodeId + 
"-%d{MM-dd-yy}.log.gz")
+                        .add(defaultLayout).addComponent(triggeringPolicy);
+        builder.add(defaultRoll);
+
+        // create the new logger
+        
builder.add(builder.newRootLogger(Level.INFO).add(builder.newAppenderRef("default")));
+
+        LayoutComponentBuilder accessLayout = 
builder.newLayout("PatternLayout").addAttribute("pattern", "%m%n");
+        AppenderComponentBuilder accessRoll = builder.newAppender("access", 
"RollingFile")
+                .addAttribute("fileName", logDir + "access-" + nodeId + ".log")
+                .addAttribute("filePattern", logDir + "access-" + nodeId + 
"-%d{MM-dd-yy}.log.gz").add(accessLayout)
+                .addComponent(triggeringPolicy);
+        builder.add(accessRoll);
+        
builder.add(builder.newLogger("org.apache.hyracks.http.server.CLFLogger", 
Level.forName("ACCESS", 550))
+                
.add(builder.newAppenderRef("access")).addAttribute("additivity", false));
+
+        return builder.build();
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, 
final ConfigurationSource source) {
+        return getConfiguration(loggerContext, source.toString(), null);
+    }
+
+    @Override
+    public Configuration getConfiguration(final LoggerContext loggerContext, 
final String name,
+            final URI configLocation) {
+        ConfigurationBuilder<BuiltConfiguration> builder = 
newConfigurationBuilder();
+        return createConfiguration(builder);
+    }
+
+    @Override
+    protected String[] getSupportedTypes() {
+        return new String[] { "*" };
+    }
+
+    @Override
+    public String toString() {
+        return "NCLogConfiguration";
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/CLFLogger.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/CLFLogger.java
 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/CLFLogger.java
new file mode 100644
index 0000000..cfbcad8
--- /dev/null
+++ 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/CLFLogger.java
@@ -0,0 +1,135 @@
+/*
+ * 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.hyracks.http.server;
+
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+import io.netty.channel.socket.nio.NioSocketChannel;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.DefaultHttpContent;
+import io.netty.handler.codec.http.DefaultHttpResponse;
+import io.netty.handler.codec.http.HttpContent;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.LastHttpContent;
+
+//Based in part on LoggingHandler from Netty
+public class CLFLogger extends ChannelDuplexHandler {
+
+    private static final Logger accessLogger = LogManager.getLogger();
+    private static final String ACCESS_LOG_LEVEL = "ACCESS";
+    private static final DateTimeFormatter DATE_TIME_FORMATTER =
+            DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss 
Z").withZone(ZoneId.systemDefault());
+    private StringBuilder logLineBuilder;
+
+    private String clientIp;
+    private Instant requestTime;
+    private String reqLine;
+    private int statusCode;
+    private long respSize;
+    private String userAgentRef;
+    private boolean lastChunk = false;
+
+    public CLFLogger() {
+        this.logLineBuilder = new StringBuilder();
+        respSize = 0;
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) {
+        if (msg instanceof HttpRequest) {
+            HttpRequest req = (HttpRequest) msg;
+            clientIp = ((NioSocketChannel) 
ctx.channel()).remoteAddress().getAddress().toString().substring(1);
+            requestTime = Instant.now();
+            reqLine = req.method().toString() + " " + req.getUri() + " " + 
req.getProtocolVersion().toString();
+            userAgentRef = headerValueOrDash("Referer", req) + " " + 
headerValueOrDash("User-Agent", req);
+            lastChunk = false;
+        }
+        ctx.fireChannelRead(msg);
+    }
+
+    private String headerValueOrDash(String headerKey, HttpRequest req) {
+        String value = req.headers().get(headerKey);
+        if (value == null) {
+            value = "-";
+        } else {
+            value = "\"" + value + "\"";
+        }
+        return value;
+
+    }
+
+    @Override
+    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise 
promise) {
+        if (msg instanceof DefaultHttpResponse) {
+            HttpResponse resp = (DefaultHttpResponse) msg;
+            statusCode = resp.status().code();
+            if (msg instanceof DefaultFullHttpResponse) {
+                lastChunk = true;
+                respSize = 
resp.headers().getInt(HttpHeaderNames.CONTENT_LENGTH);
+            }
+        } else if (msg instanceof DefaultHttpContent) {
+            HttpContent content = (DefaultHttpContent) msg;
+
+            respSize += content.content().readableBytes();
+        } else if (msg instanceof LastHttpContent) {
+            lastChunk = true;
+        }
+
+        ctx.write(msg, promise);
+    }
+
+    @Override
+    public void flush(ChannelHandlerContext ctx) throws Exception {
+        if (lastChunk) {
+            printAndPrepare();
+            lastChunk = false;
+        }
+        ctx.flush();
+    }
+
+    private void printAndPrepare() {
+        logLineBuilder.append(clientIp);
+        //identd value - not relevant here
+        logLineBuilder.append(" - ");
+        //no http auth or any auth either for that matter
+        logLineBuilder.append(" - [");
+        logLineBuilder.append(DATE_TIME_FORMATTER.format(requestTime));
+        logLineBuilder.append("] \"");
+        logLineBuilder.append(reqLine);
+        logLineBuilder.append("\"");
+        logLineBuilder.append(" ").append(statusCode);
+        logLineBuilder.append(" ").append(respSize);
+        logLineBuilder.append(" ").append(userAgentRef);
+        accessLogger.log(Level.forName(ACCESS_LOG_LEVEL, 550), 
logLineBuilder.toString());
+        respSize = 0;
+        logLineBuilder.setLength(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
index 42b47fb..343faa4 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
@@ -28,6 +28,9 @@ import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import io.netty.util.internal.logging.InternalLoggerFactory;
+import io.netty.util.internal.logging.Log4J2LoggerFactory;
+import io.netty.util.internal.logging.Log4JLoggerFactory;
 import org.apache.hyracks.http.api.IChannelClosedHandler;
 import org.apache.hyracks.http.api.IServlet;
 import org.apache.hyracks.util.MXHelper;
@@ -49,6 +52,8 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.logging.LogLevel;
 import io.netty.handler.logging.LoggingHandler;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+import io.netty.util.internal.logging.Log4J2LoggerFactory;
 
 public class HttpServer {
     // Constants
@@ -81,6 +86,10 @@ public class HttpServer {
     private Throwable cause;
     private HttpServerConfig config;
 
+    static {
+        InternalLoggerFactory.setDefaultFactory(Log4J2LoggerFactory.INSTANCE);
+    }
+
     public HttpServer(EventLoopGroup bossGroup, EventLoopGroup workerGroup, 
int port, HttpServerConfig config) {
         this(bossGroup, workerGroup, port, config, null);
     }
@@ -91,6 +100,7 @@ public class HttpServer {
         this.workerGroup = workerGroup;
         this.port = port;
         this.closedHandler = closeHandler;
+        InternalLoggerFactory.setDefaultFactory(Log4J2LoggerFactory.INSTANCE);
         this.config = config;
         ctx = new ConcurrentHashMap<>();
         servlets = new ArrayList<>();
@@ -100,11 +110,12 @@ public class HttpServer {
                 runnable -> new Thread(runnable, "HttpExecutor(port:" + port + 
")-" + threadId.getAndIncrement()));
         long directMemoryBudget = numExecutorThreads * (long) 
HIGH_WRITE_BUFFER_WATER_MARK
                 + numExecutorThreads * config.getMaxResponseChunkSize();
-        LOGGER.log(Level.INFO, "The output direct memory budget for this 
server is " + directMemoryBudget + " bytes");
+        LOGGER.log(Level.DEBUG,
+                "The output direct memory budget for this server " + "is " + 
directMemoryBudget + " bytes");
         long inputBudgetEstimate =
                 (long) config.getMaxRequestInitialLineLength() * 
(config.getRequestQueueSize() + numExecutorThreads);
         inputBudgetEstimate = inputBudgetEstimate * 2;
-        LOGGER.log(Level.INFO,
+        LOGGER.log(Level.DEBUG,
                 "The \"estimated\" input direct memory budget for this server 
is " + inputBudgetEstimate + " bytes");
         // Having multiple arenas, memory fragments, and local thread cached 
buffers
         // can cause the input memory usage to exceed estimate and custom 
buffer allocator must be used to avoid this

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/31fb2e79/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
----------------------------------------------------------------------
diff --git 
a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
index e10da64..eafee2d 100644
--- 
a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
+++ 
b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerInitializer.java
@@ -21,8 +21,11 @@ package org.apache.hyracks.http.server;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
 import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
 import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.logging.LogLevel;
+import org.apache.logging.log4j.Logger;
 
 public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
 
@@ -49,6 +52,7 @@ public class HttpServerInitializer extends 
ChannelInitializer<SocketChannel> {
         p.addLast(new HttpRequestCapacityController(server));
         p.addLast(new HttpRequestDecoder(maxRequestInitialLineLength, 
maxRequestHeaderSize, maxRequestChunkSize));
         p.addLast(new HttpResponseEncoder());
+        p.addLast(new CLFLogger());
         p.addLast(new HttpRequestAggregator(maxRequestSize));
         p.addLast(server.createHttpHandler(maxResponseChunkSize));
     }

Reply via email to