Improve debugging support in microservice. Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/720e7ff6 Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/720e7ff6 Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/720e7ff6
Branch: refs/heads/master Commit: 720e7ff6eece9535023cb6706bfc083e17d84b7c Parents: ab8f0fa Author: JamesBognar <jamesbog...@apache.org> Authored: Sun Sep 24 15:54:11 2017 -0400 Committer: JamesBognar <jamesbog...@apache.org> Committed: Sun Sep 24 15:54:11 2017 -0400 ---------------------------------------------------------------------- juneau-doc/src/main/javadoc/overview.html | 71 ++- .../juneau-examples-rest/examples.cfg | 140 ++++-- juneau-examples/juneau-examples-rest/jetty.xml | 15 +- .../juneau/examples/rest/DirectoryResource.java | 3 +- .../juneau/examples/rest/RootResources.java | 1 + .../examples/rest/SampleRemoteableServlet.java | 8 +- .../rest/addressbook/AddressBookResource.java | 7 +- .../apache/juneau/microservice/JettyLogger.java | 198 +++++++++ .../juneau/microservice/Microservice.java | 199 ++++++++- .../apache/juneau/microservice/Resource.java | 12 +- .../juneau/microservice/ResourceGroup.java | 12 +- .../juneau/microservice/ResourceJenaGroup.java | 12 +- .../juneau/microservice/RestMicroservice.java | 429 +++++++------------ .../microservice/resources/DebugResource.java | 74 ++++ .../resources/DirectoryResource.java | 3 +- .../microservice/resources/LogsResource.java | 3 +- .../juneau-microservice-template/jetty.xml | 17 +- .../my-microservice.cfg | 78 +++- .../juneau-microservice-test/jetty.xml | 15 +- .../juneau-microservice-test.cfg | 39 +- .../juneau/rest/test/AcceptCharsetResource.java | 8 +- .../juneau/rest/test/ContentResource.java | 6 +- .../apache/juneau/rest/test/ParamsResource.java | 5 +- .../java/org/apache/juneau/rest/test/Root.java | 4 +- .../rest/test/ThirdPartyProxyResource.java | 62 ++- .../apache/juneau/rest/test/HeadersTest.java | 5 +- .../juneau/rest/test/TestMicroservice.java | 17 +- .../juneau/rest/test/ThirdPartyProxyTest.java | 43 +- .../java/org/apache/juneau/rest/CallMethod.java | 10 +- .../org/apache/juneau/rest/RestCallHandler.java | 2 +- .../java/org/apache/juneau/rest/RestConfig.java | 113 +++++ .../org/apache/juneau/rest/RestContext.java | 257 ++--------- .../org/apache/juneau/rest/RestException.java | 5 +- .../juneau/rest/RestResourceResolver.java | 2 +- .../apache/juneau/rest/RestServletDefault.java | 7 +- .../apache/juneau/rest/annotation/FormData.java | 2 +- .../apache/juneau/rest/annotation/Query.java | 2 +- .../juneau/rest/annotation/RestMethod.java | 47 ++ .../juneau/rest/annotation/RestResource.java | 142 +++++- .../java/org/apache/juneau/rest/package.html | 22 +- 40 files changed, 1403 insertions(+), 694 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-doc/src/main/javadoc/overview.html ---------------------------------------------------------------------- diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html index 2ea98dc..2304c63 100644 --- a/juneau-doc/src/main/javadoc/overview.html +++ b/juneau-doc/src/main/javadoc/overview.html @@ -5439,12 +5439,12 @@ } ), + <jc>// Allow INIT as a method parameter.</jc> + allowMethodParam=<js>"*"</js>, + <jc>// Properties that get applied to all serializers and parsers.</jc> properties={ - <jc>// Allow INIT as a method parameter.</jc> - <ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>), - <jc>// Use single quotes.</jc> <ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>), @@ -6122,7 +6122,7 @@ </p> <p> The ability to overload methods is enabled through the - {@link org.apache.juneau.rest.RestContext#REST_allowMethodParam} property. + {@link org.apache.juneau.rest.annotation.RestResource#allowMethodParam()} setting. </p> </div> </div> @@ -6163,10 +6163,8 @@ <js>"options: servlet:/?method=OPTIONS"</js> } ), - properties={ - <jc>// Allow us to use method=POST from a browser.</jc> - <ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>) - } + <jc>// Allow us to use method=POST from a browser.</jc> + allowMethodParam=<js>"*"</js> ) <jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet { @@ -7448,6 +7446,7 @@ <h6 class='topic'>juneau-dto</h6> <ul class='spaced-list'> </ul> + </div> <!-- =========================================================================================================== --> @@ -7845,13 +7844,35 @@ {@link org.apache.juneau.rest.RestResourceResolver} instances are now inherited from parent resources to child resources unless explicitly overridden at the child level. <br>It's also been changed to an interface. - <li> - New setting: {@link org.apache.juneau.rest.RestContext#REST_resourceResolver}. - <br>Allows you to specify a resource resolver on the servlet context to make it easier to work with - dependency injection frameworks. - <li> - New annotation: {@link org.apache.juneau.rest.annotation.RestResource#contextPath()}. - <br>Allows you to override the context path value inherited from the servlet container. + <li>New annotations on {@link org.apache.juneau.rest.annotation.RestResource @RestResource}: + <ul> + <li>{@link org.apache.juneau.rest.annotation.RestResource#resourceResolver() resourceResolver()} + <br>Allows you to specify a resource resolver on the servlet context to make it easier to work with + dependency injection frameworks. + <li>{@link org.apache.juneau.rest.annotation.RestResource#contextPath() contextPath()} - + <br>Allows you to override the context path value inherited from the servlet container. + <li>{@link org.apache.juneau.rest.annotation.RestResource#allowHeaderParams() allowHeaderParams()} - + <br>Replaces the <code>RestContext.REST_allowHeaderParams</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#allowMethodParam() allowMethodParam()} - + <br>Replaces the <code>RestContext.REST_allowMethodParam</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#allowBodyParam() allowBodyParam()} - + <br>Replaces the <code>RestContext.REST_allowBodyParam</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#renderResponseStackTraces() renderResponseStackTraces()} - + <br>Replaces the <code>RestContext.REST_xxx</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#useStackTraceHashes() useStackTraceHashes()} - + <br>Replaces the <code>RestContext.REST_useStackTraceHashes</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#defaultCharset() defaultCharset()} - + <br>Replaces the <code>RestContext.REST_defaultCharset</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestResource#paramFormat() paramFormat()} - + <br>Replaces the <code>RestContext.REST_paramFormat</code> setting. + </ul> + <li>New annotations on {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}: + <ul> + <li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultCharset() defaultCharset()} - + <br>Replaces the <code>RestContext.REST_defaultCharset</code> setting. + <li>{@link org.apache.juneau.rest.annotation.RestMethod#paramFormat() paramFormat()} - + <br>Replaces the <code>RestContext.REST_paramFormat</code> setting. + </ul> <li> The following implementation classes can now be defined as non-static inner classes of servlets/resources: <ul> @@ -7884,12 +7905,32 @@ <h6 class='topic'>juneau-microservice</h6> <ul class='spaced-list'> <li> + The microservice has been significantly modified to be configured via a <code>jetty.xml</code> file + for maximum flexibility instead of the hodge-podge of support in the config file. + <br>Top-level servlets should now be defined in the provided <code>jetty.xml</code> file. + <li> New methods on {@link org.apache.juneau.microservice.RestMicroservice}: <ul> <li>{@link org.apache.juneau.microservice.RestMicroservice#addServlet(Servlet,String) addServlet(Servlet,String)} <li>{@link org.apache.juneau.microservice.RestMicroservice#addServletAttribute(String,Object) addServletAttribute(String,Object)} <li>{@link org.apache.juneau.microservice.RestMicroservice#getServer() getServer()} + <li>{@link org.apache.juneau.microservice.RestMicroservice#getInstance() getInstance()} + <li>{@link org.apache.juneau.microservice.RestMicroservice#getPort() getPort()} + <li>{@link org.apache.juneau.microservice.RestMicroservice#getContextPath() getContextPath()} + <li>{@link org.apache.juneau.microservice.RestMicroservice#getProtocol() getProtocol()} + <li>{@link org.apache.juneau.microservice.RestMicroservice#getHostName() getHostName()} </ul> + <li> + New methods on {@link org.apache.juneau.microservice.Microservice}: + <ul> + <li>{@link org.apache.juneau.microservice.Microservice#getInstance() getInstance()} + </ul> + <li> + New class {@link org.apache.juneau.microservice.JettyLogger} for directing Jetty logging to the + java.util.logging framework. + <li> + New class {@link org.apache.juneau.microservice.resources.DebugResource} for viewing and generating + Jetty thread dumps through REST calls. </ul> <h6 class='topic'>org.apache.juneau.rest.examples</h6> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/examples.cfg ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/examples.cfg b/juneau-examples/juneau-examples-rest/examples.cfg index b54711b..4a8e528 100755 --- a/juneau-examples/juneau-examples-rest/examples.cfg +++ b/juneau-examples/juneau-examples-rest/examples.cfg @@ -11,18 +11,40 @@ # * specific language governing permissions and limitations under the License. * # *************************************************************************************************************************** -#================================================================================ +#======================================================================================================================= # Basic configuration file for SaaS microservices # Subprojects can use this as a starting point. -#================================================================================ +#======================================================================================================================= -#================================================================================ +# What to do when the config file is saved. +# Possible values: +# NOTHING - Don't do anything. +# RESTART_SERVER - Restart the Jetty server. +# RESTART_SERVICE - Shutdown and exit with code '3'. +saveConfigAction = RESTART_SERVER + +#======================================================================================================================= +# Jetty settings +#======================================================================================================================= +[Jetty] + +# Path of the jetty.xml file used to configure the Jetty server. +config = jetty.xml + +# Resolve Juneau variables in the jetty.xml file. +resolveVars = true + +# Port to use for the jetty server. +# You can specify multiple ports. The first available will be used. '0' indicates to try a random port. +# The resulting available port gets set as the system property "availablePort" which can be referenced in the +# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled). +port = 10000,0,0,0 + +#======================================================================================================================= # REST settings -#================================================================================ +#======================================================================================================================= [REST] -jettyXml = jetty.xml - # Stylesheet to use for HTML views. # The default options are: # - styles/juneau.css @@ -31,53 +53,107 @@ jettyXml = jetty.xml # directory. stylesheet = styles/devops.css -# What to do when the config file is saved. -# Possible values: -# NOTHING - Don't do anything. -# RESTART_SERVER - Restart the Jetty server. -# RESTART_SERVICE - Shutdown and exit with code '3'. -saveConfigAction = RESTART_SERVER - -#================================================================================ +#======================================================================================================================= # Logger settings +#----------------------------------------------------------------------------------------------------------------------- # See FileHandler Java class for details. -#================================================================================ +#======================================================================================================================= [Logging] -logDir = $S{user.dir}/target/logs -logFile = sample.%g.log -dateFormat = yyyy.MM.dd hh:mm:ss -format = [{date} {level}] {msg}%n -append = false + +# The directory where to create the log file. +# Default is "." +logDir = ./target/logs + +# The name of the log file to create for the main logger. +# The logDir and logFile make up the pattern that's passed to the FileHandler +# constructor. +# If value is not specified, then logging to a file will not be set up. +logFile = microservice.%g.log + +# Whether to append to the existing log file or create a new one. +# Default is false. +append = + +# The SimpleDateFormat format to use for dates. +# Default is "yyyy.MM.dd hh:mm:ss". +dateFormat = + +# The log message format. +# The value can contain any of the following variables: +# {date} - The date, formatted per dateFormat. +# {class} - The class name. +# {method} - The method name. +# {logger} - The logger name. +# {level} - The log level name. +# {msg} - The log message. +# {threadid} - The thread ID. +# {exception} - The localized exception message. +# Default is "[{date} {level}] {msg}%n". +format = + +# The maximum log file size. +# Suffixes available for numbers. +# See ConfigFile.getInt(String,int) for details. +# Default is 1M. limit = 10M + +# Max number of log files. +# Default is 1. count = 5 -levels = { org.apache.juneau:'INFO' } + +# Default log levels. +# Format is lax-JSON. +# Keys are logger names. +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) +levels = + { + '': 'WARNING', + org.apache.juneau: 'WARNING', + org.eclipse.jetty: 'WARNING' + } + +# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier. +# Useful for preventing log files from filling up with duplicate stack traces. +# Default is false. useStackTraceHashes = true + +# The default level for the console logger. +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) +# Default is WARNING. consoleLevel = WARNING -#================================================================================ +# The default level for the file logger. +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) +# Default is INFO. +fileLevel = INFO + +#======================================================================================================================= # System properties -#-------------------------------------------------------------------------------- +#----------------------------------------------------------------------------------------------------------------------- # These are arbitrary system properties that can be set during startup. -#================================================================================ +#======================================================================================================================= [SystemProperties] # Configure Jetty for StdErrLog Logging -org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog +# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog + +# Configure Jetty to log using java-util logging +org.eclipse.jetty.util.log.class = org.apache.juneau.microservice.JettyLogger # Jetty logging level org.eclipse.jetty.LEVEL = WARN -derby.stream.error.file = $S{user.dir}/target/logs/derby.log +derby.stream.error.file = $C{Logging/logDir}/derby-errors.log -#================================================================================ +#======================================================================================================================= # DockerRegistryResource properties -#================================================================================ +#======================================================================================================================= [DockerRegistry] url = http://docker.apache.org:5000/v1 -#================================================================================ +#======================================================================================================================= # SqlQueryResource properties -#================================================================================ +#======================================================================================================================= [SqlQueryResource] driver = org.apache.derby.jdbc.EmbeddedDriver directory = $S{user.dir}/target/derby/testDB @@ -85,9 +161,9 @@ connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true allowTempUpdates = true includeRowNums = true -#================================================================================ +#======================================================================================================================= # Source code location -#================================================================================ +#======================================================================================================================= [Source] gitHub = https://github.com/apache/incubator-juneau/blob/master/juneau-examples-rest/src/main/java http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/jetty.xml ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/jetty.xml b/juneau-examples/juneau-examples-rest/jetty.xml index 2cac2e9..d3ff1aa 100644 --- a/juneau-examples/juneau-examples-rest/jetty.xml +++ b/juneau-examples/juneau-examples-rest/jetty.xml @@ -24,7 +24,7 @@ <Arg> <Ref refid="ExampleServer" /> </Arg> - <Set name="port">10000</Set> + <Set name="port">$S{availablePort,8080}</Set> </New> </Item> </Array> @@ -58,7 +58,18 @@ </Set> </New> </Set> - + + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="$C{Logging/logDir,logs}"/>/jetty-requests.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="LogTimeZone">GMT</Set> + <Set name="retainDays">90</Set> + <Set name="append">false</Set> + <Set name="LogLatency">true</Set> + </New> + </Set> + <Get name="ThreadPool"> <Set name="minThreads" type="int">10</Set> <Set name="maxThreads" type="int">100</Set> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java index 0b3799f..e72b17e 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java @@ -17,7 +17,6 @@ import static org.apache.juneau.rest.annotation.HookEvent.*; import static java.util.logging.Level.*; import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.html.HtmlDocSerializerContext.*; -import static org.apache.juneau.rest.RestContext.*; import java.io.*; import java.net.*; @@ -51,9 +50,9 @@ import org.apache.juneau.utils.*; "source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java" } ), + allowMethodParam="*", properties={ @Property(name=HTML_uriAnchorText, value=PROPERTY_NAME), - @Property(name=REST_allowMethodParam, value="*"), @Property(name="rootDir", value="$S{java.io.tmpdir}"), @Property(name="allowViews", value="false"), @Property(name="allowDeletes", value="false"), http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java index 9ee9abe..5520b5b 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java @@ -68,6 +68,7 @@ import org.apache.juneau.rest.widget.*; ConfigResource.class, LogsResource.class, DockerRegistryResource.class, + DebugResource.class, ShutdownResource.class } ) http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java index 1306d97..a5b0aa0 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java @@ -12,8 +12,6 @@ // *************************************************************************************************************************** package org.apache.juneau.examples.rest; -import static org.apache.juneau.rest.RestContext.*; - import java.util.*; import org.apache.juneau.examples.addressbook.*; @@ -44,10 +42,8 @@ import org.apache.juneau.rest.remoteable.*; "</div>" } ), - properties={ - // Allow us to use method=POST from a browser. - @Property(name=REST_allowMethodParam, value="*") - }, + // Allow us to use method=POST from a browser. + allowMethodParam="*", config="$S{juneau.configFile}" // So we can resolve $C{Source/gitHub} above. ) public class SampleRemoteableServlet extends RemoteableServlet { http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java ---------------------------------------------------------------------- diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java index 5569388..8776322 100644 --- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java +++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java @@ -16,7 +16,6 @@ import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.html.HtmlDocSerializerContext.*; import static org.apache.juneau.jena.RdfCommonContext.*; import static org.apache.juneau.jena.RdfSerializerContext.*; -import static org.apache.juneau.rest.RestContext.*; import java.util.*; @@ -82,12 +81,12 @@ import org.apache.juneau.utils.*; footer="$W{PoweredByJuneau}" ), + // Allow INIT as a method parameter. + allowMethodParam="*", + // Properties that get applied to all serializers and parsers. properties={ - // Allow INIT as a method parameter. - @Property(name=REST_allowMethodParam, value="*"), - // Use single quotes. @Property(name=SERIALIZER_quoteChar, value="'"), http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java new file mode 100644 index 0000000..1c011e8 --- /dev/null +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java @@ -0,0 +1,198 @@ +// *************************************************************************************************************************** +// * 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.juneau.microservice; + +import static java.util.logging.Level.*; +import java.util.logging.*; + +import org.apache.juneau.internal.*; +import org.eclipse.jetty.util.log.AbstractLogger; + +/** + * Implementation of Jetty {@link Logger} based on {@link java.util.logging.Logger}. + * + * <p> + * Allows Jetty to log to the Java Util logging framework (and thus to the main log file defined in the + * <cc>[Logging]</cc> section). + * + * <p> + * Can be used by setting the following system property in the microservice config file. + * + * <p class='bcode'> + * <cs>[SystemProperties]</cs> + * + * <cc># Configure Jetty to log using java-util logging</cc> + * <ck>org.eclipse.jetty.util.log.class</ck> = org.apache.juneau.microservice.JettyLogger + * </p> + * + */ +public class JettyLogger extends AbstractLogger { + private final static boolean SHOW_SOURCE = SystemUtils.getFirstBoolean(true, "org.eclipse.jetty.util.log.SOURCE", "org.eclipse.jetty.util.log.javautil.SOURCE"); + + private Level configuredLevel; + private Logger logger; + + /** + * Default constructor. + * + * <p> + * Returns the logger with name <js>"org.eclipse.jetty.util.log.javautil"</js>. + */ + public JettyLogger() { + this("org.eclipse.jetty.util.log.javautil"); + } + + /** + * Normal constructor. + * + * @param name The logger name. + */ + public JettyLogger(String name) { + logger = Logger.getLogger(name); + configuredLevel = logger.getLevel(); + } + + @Override + public String getName() { + return logger.getName(); + } + + @Override + public void warn(String msg, Object... args) { + if (isLoggable(WARNING)) + log(WARNING, format(msg, args), null); + } + + @Override + public void warn(Throwable thrown) { + if (isLoggable(WARNING)) + log(WARNING, "", thrown); + } + + @Override + public void warn(String msg, Throwable thrown) { + if (isLoggable(WARNING)) + log(WARNING, msg, thrown); + } + + @Override + public void info(String msg, Object... args) { + if (isLoggable(INFO)) + log(INFO, format(msg, args), null); + } + + @Override + public void info(Throwable thrown) { + if (isLoggable(INFO)) + log(INFO, "", thrown); + } + + @Override + public void info(String msg, Throwable thrown) { + if (isLoggable(INFO)) + log(INFO, msg, thrown); + } + + @Override + public boolean isDebugEnabled() { + return isLoggable(FINE); + } + + @Override + public void setDebugEnabled(boolean enabled) { + if (enabled) { + configuredLevel = logger.getLevel(); + logger.setLevel(FINE); + } else { + logger.setLevel(configuredLevel); + } + } + + @Override + public void debug(String msg, Object... args) { + if (isLoggable(FINE)) + log(FINE, format(msg, args), null); + } + + @Override + public void debug(String msg, long arg) { + if (isLoggable(FINE)) + log(FINE, format(msg, arg), null); + } + + @Override + public void debug(Throwable thrown) { + if (isLoggable(FINE)) + log(FINE, "", thrown); + } + + @Override + public void debug(String msg, Throwable thrown) { + if (isLoggable(FINE)) + log(FINE, msg, thrown); + } + + @Override + protected org.eclipse.jetty.util.log.Logger newLogger(String fullname) { + return new JettyLogger(fullname); + } + + @Override + public void ignore(Throwable ignored) { + if (isLoggable(FINEST)) + log(FINEST, org.eclipse.jetty.util.log.Log.IGNORED, ignored); + } + + private static String format(String msg, Object... args) { + msg = String.valueOf(msg); + if (args.length == 0) + return msg; + StringBuilder sb = new StringBuilder(); + int start = 0; + for (Object arg : args) { + int bi = msg.indexOf("{}", start); + if (bi < 0) { + sb.append(msg.substring(start)).append(" ").append(arg); + start = msg.length(); + } else { + sb.append(msg.substring(start, bi)).append(String.valueOf(arg)); + start = bi + 2; + } + } + sb.append(msg.substring(start)); + return sb.toString(); + } + + private void log(Level level, String msg, Throwable thrown) { + LogRecord r = new LogRecord(level, msg); + if (thrown != null) + r.setThrown(thrown); + r.setLoggerName(logger.getName()); + if (SHOW_SOURCE) { + StackTraceElement[] stack = new Throwable().getStackTrace(); + for (int i = 0; i < stack.length; i++) { + StackTraceElement e = stack[i]; + if (!e.getClassName().equals(getClass().getName())) { + r.setSourceClassName(e.getClassName()); + r.setSourceMethodName(e.getMethodName()); + break; + } + } + } + logger.log(r); + } + + private boolean isLoggable(Level level) { + return logger.isLoggable(level); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java index 1e7ca26..c60187b 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java @@ -12,16 +12,20 @@ // *************************************************************************************************************************** package org.apache.juneau.microservice; +import static org.apache.juneau.internal.FileUtils.*; import static org.apache.juneau.internal.IOUtils.*; +import static org.apache.juneau.internal.StringUtils.*; import java.io.*; import java.net.*; import java.util.*; import java.util.jar.*; +import java.util.logging.*; import org.apache.juneau.*; import org.apache.juneau.ini.*; import org.apache.juneau.internal.*; +import org.apache.juneau.microservice.resources.*; import org.apache.juneau.svl.*; import org.apache.juneau.svl.vars.*; import org.apache.juneau.utils.*; @@ -101,21 +105,47 @@ import org.apache.juneau.utils.*; */ public abstract class Microservice { - private static Args args; - private static ConfigFile cf; - private static ManifestFile mf; + private static volatile Microservice INSTANCE; + + private Logger logger; + private Args args; + private ConfigFile cf; + private ManifestFile mf; + private VarResolver vr; private String cfPath; /** + * Returns the Microservice instance. + * <p> + * This method only works if there's only one Microservice instance in a JVM. + * Otherwise, it's just overwritten by the last call to {@link #Microservice(String...)}. + * + * @return The Microservice instance, or <jk>null</jk> if there isn't one. + */ + public static Microservice getInstance() { + synchronized(Microservice.class) { + return INSTANCE; + } + } + + /** * Constructor. * * @param args Command line arguments. * @throws Exception */ protected Microservice(String...args) throws Exception { - Microservice.args = new Args(args); + setInstance(this); + this.args = new Args(args); } + + private static void setInstance(Microservice m) { + synchronized(Microservice.class) { + INSTANCE = m; + } + } + /** * Specifies the path of the config file for this microservice. @@ -158,8 +188,8 @@ public abstract class Microservice { * * @param cf The config file for this application, or <jk>null</jk> if no config file is needed. */ - public static void setConfig(ConfigFile cf) { - Microservice.cf = cf; + public void setConfig(ConfigFile cf) { + this.cf = cf; } /** @@ -176,8 +206,8 @@ public abstract class Microservice { * * @param mf The manifest file of this microservice. */ - public static void setManifest(Manifest mf) { - Microservice.mf = new ManifestFile(mf); + public void setManifest(Manifest mf) { + this.mf = new ManifestFile(mf); } /** @@ -189,7 +219,7 @@ public abstract class Microservice { */ public Microservice setManifestContents(String...contents) throws IOException { String s = StringUtils.join(contents, "\n") + "\n"; - Microservice.mf = new ManifestFile(new Manifest(new ByteArrayInputStream(s.getBytes("UTF-8")))); + this.mf = new ManifestFile(new Manifest(new ByteArrayInputStream(s.getBytes("UTF-8")))); return this; } @@ -199,8 +229,8 @@ public abstract class Microservice { * @param f The manifest file of this microservice. * @throws IOException If a problem occurred while trying to read the manifest file. */ - public static void setManifest(File f) throws IOException { - Microservice.mf = new ManifestFile(f); + public void setManifest(File f) throws IOException { + this.mf = new ManifestFile(f); } /** @@ -210,8 +240,8 @@ public abstract class Microservice { * @param c The class whose jar file contains the manifest to use for this microservice. * @throws IOException If a problem occurred while trying to read the manifest file. */ - public static void setManifest(Class<?> c) throws IOException { - Microservice.mf = new ManifestFile(c); + public void setManifest(Class<?> c) throws IOException { + this.mf = new ManifestFile(c); } /** @@ -285,7 +315,7 @@ public abstract class Microservice { * * @return The command-line arguments passed into the application. */ - protected static Args getArgs() { + public Args getArgs() { return args; } @@ -382,7 +412,7 @@ public abstract class Microservice { * * @return The config file for this application, or <jk>null</jk> if no config file is configured. */ - protected static ConfigFile getConfig() { + public ConfigFile getConfig() { return cf; } @@ -406,11 +436,30 @@ public abstract class Microservice { * * @return The manifest file from the main jar, or <jk>null</jk> if the manifest file could not be retrieved. */ - protected static ManifestFile getManifest() { + public ManifestFile getManifest() { return mf; } + /** + * Returns the variable resolver for resolving variables in strings and files. + * <p> + * See the {@link #createVarResolver()} method for the list of available resolution variables. + * + * @return The VarResolver used by this Microservice, or <jk>null</jk> if it was never created. + */ + public VarResolver getVarResolver() { + return vr; + } + /** + * Returns the logger for this microservice. + * + * @return The logger for this microservice. + */ + public Logger getLogger() { + return logger; + } + //-------------------------------------------------------------------------------- // Abstract lifecycle methods. //-------------------------------------------------------------------------------- @@ -492,9 +541,11 @@ public abstract class Microservice { } } + vr = createVarResolver().build(); + if (cfPath != null) System.setProperty("juneau.configFile", cfPath); - + // -------------------------------------------------------------------------------- // Set system properties. // -------------------------------------------------------------------------------- @@ -504,6 +555,16 @@ public abstract class Microservice { System.setProperty(key, cf.get("SystemProperties", key)); // -------------------------------------------------------------------------------- + // Initialize logging. + // -------------------------------------------------------------------------------- + try { + initLogging(); + } catch (Exception e) { + // If logging can be initialized, just print a stack trace and continue. + e.printStackTrace(); + } + + // -------------------------------------------------------------------------------- // Add a config file change listener. // -------------------------------------------------------------------------------- cf.addListener(new ConfigFileListener() { @@ -550,6 +611,110 @@ public abstract class Microservice { } /** + * Initialize the logging for this microservice. + * + * <p> + * Subclasses can override this method to provide customized logging. + * + * <p> + * The default implementation uses the <cs>Logging</cs> section in the config file to set up logging: + * <p class='bcode'> + * <cc>#================================================================================ + * # Logger settings + * # See FileHandler Java class for details. + * #================================================================================</cc> + * <cs>[Logging]</cs> + * + * <cc># The directory where to create the log file. + * # Default is ".".</cc> + * <ck>logDir</ck> = logs + * + * <cc># The name of the log file to create for the main logger. + * # The logDir and logFile make up the pattern that's passed to the FileHandler + * # constructor. + * # If value is not specified, then logging to a file will not be set up.</cc> + * <ck>logFile</ck> = microservice.%g.log + * + * <cc># Whether to append to the existing log file or create a new one. + * # Default is false.</cc> + * <ck>append</ck> = + * + * <cc># The SimpleDateFormat format to use for dates. + * # Default is "yyyy.MM.dd hh:mm:ss".</cc> + * <ck>dateFormat</ck> = + * + * <cc># The log message format. + * # The value can contain any of the following variables: + * # {date} - The date, formatted per dateFormat. + * # {class} - The class name. + * # {method} - The method name. + * # {logger} - The logger name. + * # {level} - The log level name. + * # {msg} - The log message. + * # {threadid} - The thread ID. + * # {exception} - The localized exception message. + * # Default is "[{date} {level}] {msg}%n".</cc> + * <ck>format</ck> = + * + * <cc># The maximum log file size. + * # Suffixes available for numbers. + * # See ConfigFile.getInt(String,int) for details. + * # Default is 1M.</cc> + * <ck>limit</ck> = 10M + * + * <cc># Max number of log files. + * # Default is 1.</cc> + * <ck>count</ck> = 5 + * + * <cc># Default log levels. + * # Keys are logger names. + * # Values are serialized Level POJOs.</cc> + * <ck>levels</ck> = { org.apache.juneau:'INFO' } + * + * <cc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier. + * # Useful for preventing log files from filling up with duplicate stack traces. + * # Default is false.</cc> + * <ck>useStackTraceHashes</ck> = true + * + * <cc># The default level for the console logger. + * # Default is WARNING.</cc> + * <ck>consoleLevel</ck> = WARNING + * </p> + * + * @throws Exception + */ + protected void initLogging() throws Exception { + ConfigFile cf = getConfig(); + logger = Logger.getLogger(""); + String logFile = cf.getString("Logging/logFile"); + if (! isEmpty(logFile)) { + LogManager.getLogManager().reset(); + String logDir = cf.getString("Logging/logDir", "."); + mkdirs(new File(logDir), false); + boolean append = cf.getBoolean("Logging/append"); + int limit = cf.getInt("Logging/limit", 1024*1024); + int count = cf.getInt("Logging/count", 1); + FileHandler fh = new FileHandler(logDir + '/' + logFile, limit, count, append); + + boolean useStackTraceHashes = cf.getBoolean("Logging/useStackTraceHashes"); + String format = cf.getString("Logging/format", "[{date} {level}] {msg}%n"); + String dateFormat = cf.getString("Logging/dateFormat", "yyyy.MM.dd hh:mm:ss"); + fh.setFormatter(new LogEntryFormatter(format, dateFormat, useStackTraceHashes)); + fh.setLevel(cf.getObjectWithDefault("Logging/fileLevel", Level.INFO, Level.class)); + logger.addHandler(fh); + + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(cf.getObjectWithDefault("Logging/consoleLevel", Level.WARNING, Level.class)); + ch.setFormatter(new LogEntryFormatter(format, dateFormat, false)); + logger.addHandler(ch); + } + ObjectMap loggerLevels = cf.getObject("Logging/levels", ObjectMap.class); + if (loggerLevels != null) + for (String l : loggerLevels.keySet()) + Logger.getLogger(l).setLevel(loggerLevels.get(l, Level.class)); + } + + /** * Joins the application with the current thread. * * <p> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java index 0579d4b..2bb1632 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java @@ -13,7 +13,6 @@ package org.apache.juneau.microservice; import static org.apache.juneau.rest.annotation.HookEvent.*; -import static javax.servlet.http.HttpServletResponse.*; import org.apache.juneau.rest.*; import org.apache.juneau.rest.annotation.*; @@ -64,11 +63,12 @@ public abstract class Resource extends RestServletDefault { */ @RestHook(INIT) public void addConfigVars(RestConfig config) throws Exception { - if (Microservice.getArgs() == null || Microservice.getConfig() == null) - throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use Resource class outside of RestMicroservice."); - config + Microservice m = Microservice.getInstance(); + if (m != null) { + config .addVars(ArgsVar.class, ManifestFileVar.class) - .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs()) - .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest()); + .addVarContextObject(ArgsVar.SESSION_args, m.getArgs()) + .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest()); + } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java index f3293cc..eab4048 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java @@ -12,7 +12,6 @@ // *************************************************************************************************************************** package org.apache.juneau.microservice; -import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.rest.annotation.HookEvent.*; import org.apache.juneau.rest.*; @@ -65,11 +64,12 @@ public abstract class ResourceGroup extends RestServletGroupDefault { */ @RestHook(INIT) public void addConfigVars(RestConfig config) throws Exception { - if (Microservice.getArgs() == null || Microservice.getConfig() == null) - throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use ResourceGroup class outside of RestMicroservice."); - config + Microservice m = Microservice.getInstance(); + if (m != null) { + config .addVars(ArgsVar.class, ManifestFileVar.class) - .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs()) - .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest()); + .addVarContextObject(ArgsVar.SESSION_args, m.getArgs()) + .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest()); + } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java index 50f2075..80e31f8 100644 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java @@ -12,7 +12,6 @@ // *************************************************************************************************************************** package org.apache.juneau.microservice; -import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.rest.annotation.HookEvent.*; import org.apache.juneau.jena.*; @@ -79,11 +78,12 @@ public abstract class ResourceJenaGroup extends RestServletGroupDefault { */ @RestHook(INIT) public void addConfigVars(RestConfig config) throws Exception { - if (Microservice.getArgs() == null || Microservice.getConfig() == null) - throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use ResourceJenaGroup class outside of RestMicroservice."); - config + Microservice m = Microservice.getInstance(); + if (m != null) { + config .addVars(ArgsVar.class, ManifestFileVar.class) - .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs()) - .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest()); + .addVarContextObject(ArgsVar.SESSION_args, m.getArgs()) + .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest()); + } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java index 8dfda47..39ce7c7 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java @@ -12,10 +12,6 @@ // *************************************************************************************************************************** package org.apache.juneau.microservice; -import static org.apache.juneau.internal.StringUtils.*; -import static org.apache.juneau.internal.FileUtils.*; -import static org.apache.juneau.internal.ClassUtils.*; - import java.io.*; import java.net.*; import java.util.*; @@ -25,11 +21,11 @@ import javax.servlet.*; import org.apache.juneau.*; import org.apache.juneau.ini.*; -import org.apache.juneau.json.*; -import org.apache.juneau.microservice.resources.*; -import org.apache.juneau.parser.*; -import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.svl.*; import org.eclipse.jetty.server.*; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.handler.*; import org.eclipse.jetty.servlet.*; import org.eclipse.jetty.xml.*; @@ -43,8 +39,7 @@ import org.eclipse.jetty.xml.*; * * <h6 class='topic'>Defining REST Resources</h6> * - * Top-level REST resources are defined by the {@link #getResourceMap()} method. - * This method can be overridden to provide a customized list of REST resources. + * Top-level REST resources are defined in the <code>jetty.xml</code> file as normal servlets. * * <h6 class='topic'>Logging</h6> * @@ -72,12 +67,24 @@ import org.eclipse.jetty.xml.*; */ public class RestMicroservice extends Microservice { - ServletContextHandler servletContextHandler; - Server server; - int port; - String contextPath; - Logger logger; - Object jettyXml; + private Server server; + private Object jettyXml; + + private static volatile RestMicroservice INSTANCE; + + /** + * Returns the Microservice instance. + * <p> + * This method only works if there's only one Microservice instance in a JVM. + * Otherwise, it's just overwritten by the last call to {@link #RestMicroservice(String...)}. + * + * @return The Microservice instance, or <jk>null</jk> if there isn't one. + */ + public static RestMicroservice getInstance() { + synchronized(RestMicroservice.class) { + return INSTANCE; + } + } /** * Main method. @@ -100,8 +107,14 @@ public class RestMicroservice extends Microservice { */ public RestMicroservice(String...args) throws Exception { super(args); + setInstance(this); + } + + private static void setInstance(RestMicroservice rm) { + synchronized(RestMicroservice.class) { + INSTANCE = rm; + } } - //-------------------------------------------------------------------------------- // Methods implemented on Microservice API @@ -110,12 +123,6 @@ public class RestMicroservice extends Microservice { @Override /* Microservice */ public RestMicroservice start() throws Exception { super.start(); - try { - initLogging(); - } catch (Exception e) { - // If logging can be initialized, just print a stack trace and continue. - e.printStackTrace(); - } createServer(); startServer(); return this; @@ -132,6 +139,7 @@ public class RestMicroservice extends Microservice { Thread t = new Thread() { @Override /* Thread */ public void run() { + Logger logger = getLogger(); try { if (server.isStopping() || server.isStopped()) return; @@ -162,131 +170,85 @@ public class RestMicroservice extends Microservice { /** * Returns the port that this microservice started up on. + * <p> + * The value is determined by looking at the <code>Server/Connectors[ServerConnector]/port</code> value in the + * Jetty configuration. + * * @return The port that this microservice started up on. */ public int getPort() { - return port; + for (Connector c : getServer().getConnectors()) + if (c instanceof ServerConnector) + return ((ServerConnector)c).getPort(); + throw new RuntimeException("Could not locate ServerConnector in Jetty server."); + } + + /** + * Returns the context path that this microservice is using. + * <p> + * The value is determined by looking at the <code>Server/Handlers[ServletContextHandler]/contextPath</code> value + * in the Jetty configuration. + * + * @return The context path that this microservice is using. + */ + public String getContextPath() { + for (Handler h : getServer().getHandlers()) { + if (h instanceof HandlerCollection) { + for (Handler h2 : ((HandlerCollection)h).getChildHandlers()) + if (h2 instanceof ServletContextHandler) + return ((ServletContextHandler)h2).getContextPath(); + } + if (h instanceof ServletContextHandler) + return ((ServletContextHandler)h).getContextPath(); + } + throw new RuntimeException("Could not locate ServletContextHandler in Jetty server."); + } + + /** + * Returns whether this microservice is using <js>"http"</js> or <js>"https"</js>. + * <p> + * The value is determined by looking for the existence of an SSL Connection Factorie by looking for the + * <code>Server/Connectors[ServerConnector]/ConnectionFactories[SslConnectionFactory]</code> value in the Jetty + * configuration. + * + * @return Whether this microservice is using <js>"http"</js> or <js>"https"</js>. + */ + public String getProtocol() { + for (Connector c : getServer().getConnectors()) + if (c instanceof ServerConnector) + for (ConnectionFactory cf : ((ServerConnector)c).getConnectionFactories()) + if (cf instanceof SslConnectionFactory) + return "https"; + return "http"; } /** - * Returns the URI where this microservice is listening on. - * @return The URI where this microservice is listening on. + * Returns the hostname of this microservice. + * <p> + * Simply uses <code>InetAddress.getLocalHost().getHostName()</code>. + * + * @return The hostname of this microservice. */ - public URI getURI() { - String scheme = getConfig().getBoolean("REST/useSsl") ? "https" : "http"; + public String getHostName() { String hostname = "localhost"; - String ctx = "/".equals(contextPath) ? null : contextPath; try { hostname = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) {} - try { - return new URI(scheme, null, hostname, port, ctx, null, null); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + return hostname; } - + /** - * Initialize the logging for this microservice. - * - * <p> - * Subclasses can override this method to provide customized logging. + * Returns the URI where this microservice is listening on. * - * <p> - * The default implementation uses the <cs>Logging</cs> section in the config file to set up logging: - * <p class='bcode'> - * <cc>#================================================================================ - * # Logger settings - * # See FileHandler Java class for details. - * #================================================================================</cc> - * <cs>[Logging]</cs> - * - * <cc># The directory where to create the log file. - * # Default is ".".</cc> - * <ck>logDir</ck> = logs - * - * <cc># The name of the log file to create for the main logger. - * # The logDir and logFile make up the pattern that's passed to the FileHandler - * # constructor. - * # If value is not specified, then logging to a file will not be set up.</cc> - * <ck>logFile</ck> = microservice.%g.log - * - * <cc># Whether to append to the existing log file or create a new one. - * # Default is false.</cc> - * <ck>append</ck> = - * - * <cc># The SimpleDateFormat format to use for dates. - * # Default is "yyyy.MM.dd hh:mm:ss".</cc> - * <ck>dateFormat</ck> = - * - * <cc># The log message format. - * # The value can contain any of the following variables: - * # {date} - The date, formatted per dateFormat. - * # {class} - The class name. - * # {method} - The method name. - * # {logger} - The logger name. - * # {level} - The log level name. - * # {msg} - The log message. - * # {threadid} - The thread ID. - * # {exception} - The localized exception message. - * # Default is "[{date} {level}] {msg}%n".</cc> - * <ck>format</ck> = - * - * <cc># The maximum log file size. - * # Suffixes available for numbers. - * # See ConfigFile.getInt(String,int) for details. - * # Default is 1M.</cc> - * <ck>limit</ck> = 10M - * - * <cc># Max number of log files. - * # Default is 1.</cc> - * <ck>count</ck> = 5 - * - * <cc># Default log levels. - * # Keys are logger names. - * # Values are serialized Level POJOs.</cc> - * <ck>levels</ck> = { org.apache.juneau:'INFO' } - * - * <cc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier. - * # Useful for preventing log files from filling up with duplicate stack traces. - * # Default is false.</cc> - * <ck>useStackTraceHashes</ck> = true - * - * <cc># The default level for the console logger. - * # Default is WARNING.</cc> - * <ck>consoleLevel</ck> = WARNING - * </p> - * - * @throws Exception + * @return The URI where this microservice is listening on. */ - protected void initLogging() throws Exception { - ConfigFile cf = getConfig(); - logger = Logger.getLogger(""); - String logFile = cf.getString("Logging/logFile"); - if (! isEmpty(logFile)) { - LogManager.getLogManager().reset(); - String logDir = cf.getString("Logging/logDir", "."); - mkdirs(new File(logDir), false); - boolean append = cf.getBoolean("Logging/append"); - int limit = cf.getInt("Logging/limit", 1024*1024); - int count = cf.getInt("Logging/count", 1); - FileHandler fh = new FileHandler(logDir + '/' + logFile, limit, count, append); - - boolean useStackTraceHashes = cf.getBoolean("Logging/useStackTraceHashes"); - String format = cf.getString("Logging/format", "[{date} {level}] {msg}%n"); - String dateFormat = cf.getString("Logging/dateFormat", "yyyy.MM.dd hh:mm:ss"); - fh.setFormatter(new LogEntryFormatter(format, dateFormat, useStackTraceHashes)); - logger.addHandler(fh); - - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.parse(cf.getString("Logging/consoleLevel", "WARNING"))); - ch.setFormatter(new LogEntryFormatter(format, dateFormat, false)); - logger.addHandler(ch); + public URI getURI() { + String cp = getContextPath(); + try { + return new URI(getProtocol(), null, getHostName(), getPort(), "/".equals(cp) ? null : cp, null, null); + } catch (URISyntaxException e) { + throw new RuntimeException(e); } - ObjectMap loggerLevels = cf.getObject("Logging/levels", ObjectMap.class); - if (loggerLevels != null) - for (String l : loggerLevels.keySet()) - Logger.getLogger(l).setLevel(loggerLevels.get(l, Level.class)); } /** @@ -300,22 +262,22 @@ public class RestMicroservice extends Microservice { * if a jetty.xml is not specified via a <code>REST/jettyXml</code> setting: * <p class='bcode'> * <cc>#================================================================================ - * # REST settings + * # Jetty settings * #================================================================================</cc> - * <cs>[REST]</cs> - * - * <cc># The HTTP port number to use. - * # Default is Rest-Port setting in manifest file, or 8000. - * # Can also specify a comma-delimited lists of ports to try, including 0 meaning - * # try a random port.</cc> - * <ck>port</ck> = 10000 - * - * <cc># The context root of the Jetty server. - * # Default is Rest-ContextPath in manifest file, or "/".</cc> - * <ck>contextPath</ck> = - * - * <cc># Enable SSL support.</cc> - * <ck>useSsl</ck> = false + * <cs>[Jetty]</cs> + * + * <cc># Path of the jetty.xml file used to configure the Jetty server.</cc> + * <ck>config</ck> = jetty.xml + * + * <cc># Resolve Juneau variables in the jetty.xml file.</cc> + * <ck>resolveVars</ck> = true + * + * <cc># Port to use for the jetty server. + * # You can specify multiple ports. The first available will be used. '0' indicates to try a random port. + * # The resulting available port gets set as the system property "availablePort" which can be referenced in the + * # jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).</cc> + * <ck>port</ck> = 10000,0,0,0 + * </p> * * @return The newly-created server. * @throws Exception @@ -325,47 +287,41 @@ public class RestMicroservice extends Microservice { ConfigFile cf = getConfig(); ObjectMap mf = getManifest(); + VarResolver vr = getVarResolver(); + + int[] ports = cf.getObjectWithDefault("Jetty/port", mf.getWithDefault("Jetty-Port", new int[]{8000}, int[].class), int[].class); + int availablePort = findOpenPort(ports); + System.setProperty("availablePort", String.valueOf(availablePort)); + if (jettyXml == null) - jettyXml = cf.getString("REST/jettyXml", mf.getString("Rest-JettyXml", null)); - if (jettyXml != null) { - InputStream is = null; - if (jettyXml instanceof String) { - jettyXml = new File(jettyXml.toString()); - } - if (jettyXml instanceof File) { - File f = (File)jettyXml; - if (f.exists()) - is = new FileInputStream((File)jettyXml); - else - throw new FormattedRuntimeException("Jetty.xml file ''{0}'' was specified but not found on the file system.", jettyXml); - } else if (jettyXml instanceof InputStream) { - is = (InputStream)jettyXml; - } - - XmlConfiguration config = new XmlConfiguration(is); - server = (Server)config.configure(); + jettyXml = cf.getString("Jetty/config", mf.getString("Jetty-Config", null)); + if (jettyXml == null) + throw new FormattedRuntimeException("Jetty.xml file location was not specified in the configuration file (Jetty/config) or manifest file (Jetty-Config)."); + + String xmlConfig = null; + + if (jettyXml instanceof String) + jettyXml = new File(jettyXml.toString()); + + if (jettyXml instanceof File) { + File f = (File)jettyXml; + if (f.exists()) + xmlConfig = IOUtils.read((File)jettyXml); + else + throw new FormattedRuntimeException("Jetty.xml file ''{0}'' was specified but not found on the file system.", jettyXml); } else { - int[] ports = cf.getObjectWithDefault("REST/port", mf.getWithDefault("Rest-Port", new int[]{8000}, int[].class), int[].class); - - port = findOpenPort(ports); - if (port == 0) { - System.err.println("Open port not found. Tried " + JsonSerializer.DEFAULT_LAX.toString(ports)); - System.exit(1); - } - - contextPath = cf.getString("REST/contextPath", mf.getString("Rest-ContextPath", "/")); - server = new Server(port); - - servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); - - servletContextHandler.setContextPath(contextPath); - server.setHandler(servletContextHandler); - - for (Map.Entry<String,Class<? extends Servlet>> e : getResourceMap().entrySet()) - servletContextHandler.addServlet(e.getValue(), e.getKey()).setInitOrder(0); + xmlConfig = IOUtils.read(jettyXml); } + if (cf.getBoolean("Jetty/resolveVars", false)) + xmlConfig = vr.resolve(xmlConfig); + + getLogger().info(xmlConfig); + + XmlConfiguration config = new XmlConfiguration(new ByteArrayInputStream(xmlConfig.getBytes())); + server = (Server)config.configure(); + return server; } @@ -378,11 +334,14 @@ public class RestMicroservice extends Microservice { * @throws RuntimeException if {@link #createServer()} has not previously been called. */ public RestMicroservice addServlet(Servlet servlet, String pathSpec) { - if (servletContextHandler == null) - throw new RuntimeException("Servlet context handler not found. createServer() must be called first."); - ServletHolder sh = new ServletHolder(servlet); - servletContextHandler.addServlet(sh, pathSpec); - return this; + for (Handler h : getServer().getHandlers()) { + if (h instanceof ServletContextHandler) { + ServletHolder sh = new ServletHolder(servlet); + ((ServletContextHandler)h).addServlet(sh, pathSpec); + return this; + } + } + throw new RuntimeException("Servlet context handler not found in jetty server."); } /** @@ -394,9 +353,7 @@ public class RestMicroservice extends Microservice { * @throws RuntimeException if {@link #createServer()} has not previously been called. */ public RestMicroservice addServletAttribute(String name, Object value) { - if (server == null) - throw new RuntimeException("Server not found. createServer() must be called first."); - server.setAttribute(name, value); + getServer().setAttribute(name, value); return this; } @@ -406,6 +363,8 @@ public class RestMicroservice extends Microservice { * @return The underlying Jetty server, or <jk>null</jk> if {@link #createServer()} has not yet been called. */ public Server getServer() { + if (server == null) + throw new RuntimeException("Server not found. createServer() must be called first."); return server; } @@ -435,85 +394,9 @@ public class RestMicroservice extends Microservice { protected int startServer() throws Exception { onStartServer(); server.start(); - this.port = ((ServerConnector)server.getConnectors()[0]).getLocalPort(); - logger.warning("Server started on port " + port); + getLogger().warning("Server started on port " + getPort()); onPostStartServer(); - return port; - } - - /** - * Returns the resource map to use for this microservice. - * - * <p> - * Subclasses can override this method to programmatically specify their resources. - * - * <p> - * The default implementation is configured by the following values in the config file: - * <p class='bcode'> - * - * <cc>#================================================================================ - * # REST settings - * #================================================================================</cc> - * <cs>[REST]</cs> - * - * <cc># A JSON map of servlet paths to servlet classes. - * # Example: - * # resourceMap = {'/*':'com.foo.MyServlet'} - * # Either resourceMap or resources must be specified if it's not defined in - * # the manifest file.</cc> - * <ck>resourceMap</ck> = - * - * <cc># A comma-delimited list of names of classes that extend from Servlet. - * # Resource paths are pulled from @RestResource.path() annotation, or - * # "/*" if annotation not specified. - * # Example: - * # resources = com.foo.MyServlet - * * # Default is Rest-Resources in manifest file. - * # Either resourceMap or resources must be specified if it's not defined in - * # the manifest file.</cc> - * <ck>resources</ck> = - * </p> - * - * <p> - * In most cases, the rest resources will be specified in the manifest file since it's not likely to be a - * configurable property: - * <p class='bcode'> - * <mk>Rest-Resources:</mk> org.apache.juneau.microservice.sample.RootResources - * </p> - * - * @return The map of REST resources. - * @throws ClassNotFoundException - * @throws ParseException - */ - @SuppressWarnings("unchecked") - protected Map<String,Class<? extends Servlet>> getResourceMap() throws ClassNotFoundException, ParseException { - ConfigFile cf = getConfig(); - ObjectMap mf = getManifest(); - Map<String,Class<? extends Servlet>> rm = new LinkedHashMap<String,Class<? extends Servlet>>(); - - ObjectMap resourceMap = cf.getObject("REST/resourceMap", ObjectMap.class); - String[] resources = cf.getStringArray("REST/resources", mf.getStringArray("Rest-Resources")); - - if (resourceMap != null && ! resourceMap.isEmpty()) { - for (Map.Entry<String,Object> e : resourceMap.entrySet()) { - Class<?> c = Class.forName(e.getValue().toString()); - if (! isParentClass(Servlet.class, c)) - throw new ClassNotFoundException("Invalid class specified as resource. Must be a Servlet. Class='"+c.getName()+"'"); - rm.put(e.getKey(), (Class<? extends Servlet>)c); - } - } else if (resources.length > 0) { - for (String resource : resources) { - Class<?> c = Class.forName(resource); - if (! isParentClass(Servlet.class, c)) - throw new ClassNotFoundException("Invalid class specified as resource. Must be a Servlet. Class='"+c.getName()+"'"); - RestResource rr = c.getAnnotation(RestResource.class); - String path = rr == null ? "/*" : rr.path(); - if (! path.endsWith("*")) - path += (path.endsWith("/") ? "*" : "/*"); - rm.put(path, (Class<? extends Servlet>)c); - } - } - return rm; + return getPort(); } /** @@ -522,8 +405,6 @@ public class RestMicroservice extends Microservice { * <p> * The default behavior is configured by the following value in the config file: * <p class='bcode'> - * <cs>[REST]</cs> - * * <cc># What to do when the config file is saved. * # Possible values: * # NOTHING - Don't do anything. (default) @@ -535,7 +416,7 @@ public class RestMicroservice extends Microservice { @Override /* Microservice */ protected void onConfigSave(ConfigFile cf) { try { - String saveConfigAction = cf.getString("REST/saveConfigAction", "NOTHING"); + String saveConfigAction = cf.getString("saveConfigAction", "NOTHING"); if (saveConfigAction.equals("RESTART_SERVER")) { new Thread() { @Override /* Thread */ @@ -544,7 +425,7 @@ public class RestMicroservice extends Microservice { RestMicroservice.this.stop(); RestMicroservice.this.start(); } catch (Exception e) { - logger.log(Level.SEVERE, e.getLocalizedMessage(), e); + getLogger().log(Level.SEVERE, e.getLocalizedMessage(), e); } } }.start(); @@ -573,7 +454,7 @@ public class RestMicroservice extends Microservice { * @return This object (for method chaining). */ public RestMicroservice setJettyXml(Object jettyXml) { - if (jettyXml instanceof String || jettyXml instanceof File || jettyXml instanceof InputStream) + if (jettyXml instanceof String || jettyXml instanceof File || jettyXml instanceof InputStream || jettyXml instanceof Reader) this.jettyXml = jettyXml; else throw new FormattedRuntimeException("Invalid object type passed to setJettyXml()", jettyXml == null ? null : jettyXml.getClass().getName()); http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java new file mode 100644 index 0000000..8051a72 --- /dev/null +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java @@ -0,0 +1,74 @@ +// *************************************************************************************************************************** +// * 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.juneau.microservice.resources; + +import java.io.*; + +import org.apache.juneau.internal.*; +import org.apache.juneau.microservice.*; +import org.apache.juneau.rest.*; +import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.rest.labels.*; + +/** + * Microservice debug utilities. + */ +@RestResource( + path="/debug", + title="Debug", + description="Debug Utilities.", + htmldoc=@HtmlDoc( + links={ + "up: request:/..", + "jetty-thread-dump: servlet:/jetty/dump?method=POST", + "options: servlet:/?method=OPTIONS" + } + ), + allowMethodParam="OPTIONS,POST" +) +@SuppressWarnings("javadoc") +public class DebugResource extends Resource { + private static final long serialVersionUID = 1L; + + /** + * [GET /] - Shows child utilities. + * + * @return Child utility links. + * @throws Exception + */ + @RestMethod(name="GET", path="/", description="Show contents of config file.") + public ResourceDescription[] getChildren() throws Exception { + return new ResourceDescription[] { + new ResourceDescription("jetty/dump", "Jetty thread dump") + }; + } + + /** + * [GET /jetty/dump] - Generates and retrieves the jetty thread dump. + */ + @RestMethod(name="GET", path="/jetty/dump", description="Generates and retrieves the jetty thread dump.") + public Reader getJettyDump(RestRequest req, RestResponse res) { + res.setContentType("text/plain"); + return new StringReader(RestMicroservice.getInstance().getServer().dump()); + } + + /** + * [POST /jetty/dump] - Generates and saves the jetty thread dump file to jetty-thread-dump.log. + */ + @RestMethod(name="POST", path="/jetty/dump", description="Generates and saves the jetty thread dump file to jetty-thread-dump.log.") + public String createJettyDump(RestRequest req, RestResponse res) throws Exception { + String dump = RestMicroservice.getInstance().getServer().dump(); + IOUtils.pipe(dump, new FileWriter(req.getConfigFile().getString("Logging/logDir") + "/jetty-thread-dump.log")); + return "OK"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java index 0c0edc4..744b3a1 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java @@ -15,7 +15,6 @@ package org.apache.juneau.microservice.resources; import static java.util.logging.Level.*; import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.html.HtmlDocSerializerContext.*; -import static org.apache.juneau.rest.RestContext.*; import java.io.*; import java.net.*; @@ -69,9 +68,9 @@ import org.apache.juneau.utils.*; "options: servlet:/?method=OPTIONS" } ), + allowMethodParam="*", properties={ @Property(name=HTML_uriAnchorText, value=PROPERTY_NAME), - @Property(name=REST_allowMethodParam, value="*"), @Property(name="DirectoryResource.rootDir", value="") } ) http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java index d98b77d..4e9938f 100755 --- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java +++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java @@ -14,7 +14,6 @@ package org.apache.juneau.microservice.resources; import static javax.servlet.http.HttpServletResponse.*; import static org.apache.juneau.html.HtmlDocSerializerContext.*; -import static org.apache.juneau.rest.RestContext.*; import static org.apache.juneau.rest.annotation.HookEvent.*; import static org.apache.juneau.internal.StringUtils.*; @@ -44,7 +43,7 @@ import org.apache.juneau.transforms.*; properties={ @Property(name=HTML_uriAnchorText, value=PROPERTY_NAME), }, - flags={REST_allowMethodParam}, + allowMethodParam="*", pojoSwaps={ IteratorSwap.class, // Allows Iterators and Iterables to be serialized. DateSwap.ISO8601DT.class // Serialize Date objects as ISO8601 strings. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-template/jetty.xml ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-template/jetty.xml b/juneau-microservice/juneau-microservice-template/jetty.xml index 77c5cf0..3fc3408 100644 --- a/juneau-microservice/juneau-microservice-template/jetty.xml +++ b/juneau-microservice/juneau-microservice-template/jetty.xml @@ -24,7 +24,7 @@ <Arg> <Ref refid="ExampleServer" /> </Arg> - <Set name="port">10000</Set> + <Set name="port">$S{availablePort,8080}</Set> </New> </Item> </Array> @@ -55,11 +55,22 @@ </Set> </New> </Set> - + + <Set name="requestLog"> + <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> + <Set name="filename"><Property name="jetty.logs" default="$C{Logging/logDir,logs}"/>/jetty-requests.log</Set> + <Set name="filenameDateFormat">yyyy_MM_dd</Set> + <Set name="LogTimeZone">GMT</Set> + <Set name="retainDays">90</Set> + <Set name="append">false</Set> + <Set name="LogLatency">true</Set> + </New> + </Set> + <Get name="ThreadPool"> <Set name="minThreads" type="int">10</Set> <Set name="maxThreads" type="int">100</Set> <Set name="idleTimeout" type="int">60000</Set> <Set name="detailedDump">true</Set> - </Get> + </Get> </Configure> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-template/my-microservice.cfg ---------------------------------------------------------------------- diff --git a/juneau-microservice/juneau-microservice-template/my-microservice.cfg b/juneau-microservice/juneau-microservice-template/my-microservice.cfg index 2f461a3..41c7ed9 100755 --- a/juneau-microservice/juneau-microservice-template/my-microservice.cfg +++ b/juneau-microservice/juneau-microservice-template/my-microservice.cfg @@ -11,18 +11,40 @@ # * specific language governing permissions and limitations under the License. * # *************************************************************************************************************************** -#================================================================================ +#======================================================================================================================= # Basic configuration file for SaaS microservices # Subprojects can use this as a starting point. -#================================================================================ +#======================================================================================================================= -#================================================================================ +# What to do when the config file is saved. +# Possible values: +# NOTHING - Don't do anything. (default) +# RESTART_SERVER - Restart the Jetty server. +# RESTART_SERVICE - Shutdown and exit with code '3'. +saveConfigAction = RESTART_SERVER + +#======================================================================================================================= +# Jetty settings +#======================================================================================================================= +[Jetty] + +# Path of the jetty.xml file used to configure the Jetty server. +config = jetty.xml + +# Resolve Juneau variables in the jetty.xml file. +resolveVars = true + +# Port to use for the jetty server. +# You can specify multiple ports. The first available will be used. '0' indicates to try a random port. +# The resulting available port gets set as the system property "availablePort" which can be referenced in the +# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled). +port = 10000,0,0,0 + +#======================================================================================================================= # REST settings -#================================================================================ +#======================================================================================================================= [REST] -jettyXml = jetty.xml - # Stylesheet to use for HTML views. # The default options are: # - servlet:/styles/juneau.css @@ -30,17 +52,11 @@ jettyXml = jetty.xml # Other stylesheets can be referenced relative to the servlet package or working directory. stylesheet = servlet:/styles/devops.css -# What to do when the config file is saved. -# Possible values: -# NOTHING - Don't do anything. (default) -# RESTART_SERVER - Restart the Jetty server. -# RESTART_SERVICE - Shutdown and exit with code '3'. -saveConfigAction = RESTART_SERVER - -#================================================================================ +#======================================================================================================================= # Logger settings +#----------------------------------------------------------------------------------------------------------------------- # See FileHandler Java class for details. -#================================================================================ +#======================================================================================================================= [Logging] # The directory where to create the log file. @@ -85,9 +101,15 @@ limit = 10M count = 5 # Default log levels. +# Format is lax-JSON. # Keys are logger names. -# Values are serialized Level POJOs. -levels = { org.apache.juneau:'INFO' } +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) +levels = + { + '': 'WARNING', + org.apache.juneau: 'WARNING', + org.eclipse.jetty: 'WARNING' + } # Only print unique stack traces once and then refer to them by a simple 8 character hash identifier. # Useful for preventing log files from filling up with duplicate stack traces. @@ -95,18 +117,30 @@ levels = { org.apache.juneau:'INFO' } useStackTraceHashes = true # The default level for the console logger. +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) # Default is WARNING. -consoleLevel = +consoleLevel = WARNING + +# The default level for the file logger. +# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST) +# Default is INFO. +fileLevel = INFO -#================================================================================ +#======================================================================================================================= # System properties -#-------------------------------------------------------------------------------- +#----------------------------------------------------------------------------------------------------------------------- # These are arbitrary system properties that are set during startup. -#================================================================================ +#======================================================================================================================= [SystemProperties] # Configure Jetty for StdErrLog Logging -org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog +# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog + +# Configure Jetty to log using java-util logging +org.eclipse.jetty.util.log.class = org.apache.juneau.microservice.JettyLogger # Jetty logging level +# Possible values: ALL, DEBUG, INFO, WARN, OFF org.eclipse.jetty.LEVEL = WARN + +derby.stream.error.file = $C{Logging/logDir}/derby-errors.log