From a1a07e473b6cd09b506105674317b022e8143e47 Mon Sep 17 00:00:00 2001 From: Hannes Ebner Date: Thu, 31 Mar 2022 15:22:25 +0200 Subject: [PATCH] Initial commit --- .gitignore | 4 + build.sh | 3 + pom.xml | 191 ++++++++++++++++++ standalone/common/pom.xml | 44 ++++ .../recruit/RestApplicationStandalone.java | 135 +++++++++++++ standalone/jetty/pom.xml | 80 ++++++++ .../RestApplicationStandaloneJetty.java | 10 + standalone/pom.xml | 22 ++ webapp/pom.xml | 134 ++++++++++++ .../recruit/RestApplication.java | 135 +++++++++++++ .../recruit/resources/BaseResource.java | 104 ++++++++++ .../recruit/resources/DefaultResource.java | 22 ++ .../recruit/resources/StatusResource.java | 43 ++++ webapp/src/main/resources/VERSION.txt | 1 + webapp/src/main/resources/log4j2.properties | 14 ++ 15 files changed, 942 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 pom.xml create mode 100644 standalone/common/pom.xml create mode 100644 standalone/common/src/main/java/se/metasolutions/recruit/RestApplicationStandalone.java create mode 100644 standalone/jetty/pom.xml create mode 100644 standalone/jetty/src/main/java/se/metasolutions/recruit/RestApplicationStandaloneJetty.java create mode 100644 standalone/pom.xml create mode 100644 webapp/pom.xml create mode 100644 webapp/src/main/java/se/metasolutions/recruit/RestApplication.java create mode 100644 webapp/src/main/java/se/metasolutions/recruit/resources/BaseResource.java create mode 100644 webapp/src/main/java/se/metasolutions/recruit/resources/DefaultResource.java create mode 100644 webapp/src/main/java/se/metasolutions/recruit/resources/StatusResource.java create mode 100644 webapp/src/main/resources/VERSION.txt create mode 100644 webapp/src/main/resources/log4j2.properties diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f464147 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +pom.xml.versionsBackup +*.iml +target diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..6c652d3 --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +mvn $1 $2 -Dmaven.test.skip=true install diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3bad4bc --- /dev/null +++ b/pom.xml @@ -0,0 +1,191 @@ + + + 4.0.0 + + se.metasolutions.recruit + rest-parent + 1.0-SNAPSHOT + REST + pom + + + 3.0 + + + + 1.7.30 + 2.17.1 + 2.4.3 + 9.4.44.v20210927 + 3.1.0 + 20201115 + 30.1-jre + 11 + + + + standalone + webapp + + + + MetaSolutions AB + https://www.metasolutions.se + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + org.codehaus.mojo + appassembler-maven-plugin + 2.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.release} + UTF-8 + + + + + + + + EntryStore + https://maven.entrystore.org + + + Restlet + https://maven.restlet.talend.com + + + + + + + + + + org.eclipse.jetty + jetty-alpn-client + ${jetty.version} + + + org.eclipse.jetty + jetty-alpn-java-client + ${jetty.version} + + + org.eclipse.jetty + jetty-alpn-java-server + ${jetty.version} + + + org.eclipse.jetty + jetty-client + ${jetty.version} + + + org.eclipse.jetty + jetty-continuation + ${jetty.version} + + + org.eclipse.jetty + jetty-deploy + ${jetty.version} + + + org.eclipse.jetty + jetty-http + ${jetty.version} + + + org.eclipse.jetty + jetty-io + ${jetty.version} + + + org.eclipse.jetty + jetty-jmx + ${jetty.version} + + + org.eclipse.jetty + jetty-rewrite + ${jetty.version} + + + org.eclipse.jetty + jetty-security + ${jetty.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + org.eclipse.jetty + jetty-servlets + ${jetty.version} + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.eclipse.jetty + jetty-webapp + ${jetty.version} + + + org.eclipse.jetty + jetty-xml + ${jetty.version} + + + org.eclipse.jetty.http2 + http2-client + ${jetty.version} + + + org.eclipse.jetty.http2 + http2-common + ${jetty.version} + + + org.eclipse.jetty.http2 + http2-hpack + ${jetty.version} + + + org.eclipse.jetty.http2 + http2-http-client-transport + ${jetty.version} + + + org.eclipse.jetty.http2 + http2-server + ${jetty.version} + + + + + diff --git a/standalone/common/pom.xml b/standalone/common/pom.xml new file mode 100644 index 0000000..490b41d --- /dev/null +++ b/standalone/common/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + rest-standalone-common + 1.0-SNAPSHOT + jar + REST Standalone Common + + + se.metasolutions.recruit + rest-standalone + 1.0-SNAPSHOT + + + + + + src/main/resources + + + + + + + se.metasolutions.recruit + rest-webapp + ${project.version} + + + javax.servlet + javax.servlet-api + ${servlet.version} + + + commons-cli + commons-cli + 1.4 + + + + diff --git a/standalone/common/src/main/java/se/metasolutions/recruit/RestApplicationStandalone.java b/standalone/common/src/main/java/se/metasolutions/recruit/RestApplicationStandalone.java new file mode 100644 index 0000000..608ac93 --- /dev/null +++ b/standalone/common/src/main/java/se/metasolutions/recruit/RestApplicationStandalone.java @@ -0,0 +1,135 @@ +package se.metasolutions.recruit; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PatternOptionBuilder; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; +import org.restlet.Application; +import org.restlet.Component; +import org.restlet.Context; +import org.restlet.Server; +import org.restlet.data.Protocol; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.URISyntaxException; + +public abstract class RestApplicationStandalone extends Application { + + private final static org.slf4j.Logger log = LoggerFactory.getLogger(RestApplicationStandalone.class); + + public static void main(String[] args) { + System.setProperty("org.restlet.engine.loggerFacadeClass", "org.restlet.ext.slf4j.Slf4jLoggerFacade"); + + CommandLineParser parser = new DefaultParser(); + Options options = new Options(); + options.addOption(Option.builder("p"). + longOpt("port"). + desc("port to listen on; default: 8282"). + hasArg(). + argName("PORT"). + optionalArg(false). + type(PatternOptionBuilder.NUMBER_VALUE). + build()); + options.addOption(Option.builder("l"). + longOpt("log-level"). + desc("log level, one of: ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF; default: INFO"). + hasArg(). + argName("LEVEL"). + optionalArg(false). + build()); + options.addOption(Option.builder(). + longOpt("connector-params"). + desc("comma separated list of parameters to be used for the server connector." + + "Example for Jetty: \"threadPool.minThreads=50,threadPool.maxThreads=250\"; " + + "see the JavaDoc of JettyServerHelper for available parameters"). + hasArg(). + argName("SETTINGS"). + optionalArg(false). + build()); + options.addOption(Option.builder("h").longOpt("help").desc("display this help").build()); + + CommandLine cl = null; + try { + cl = parser.parse(options, args); + } catch (ParseException e) { + System.err.println(e.getMessage() + "\n"); + printHelp(options); + System.exit(1); + } + + if (cl.hasOption("help")) { + printHelp(options); + System.exit(0); + } + + String strPort = cl.getOptionValue("p", "8282"); + int port = 8282; + try { + port = Integer.parseInt(strPort); + } catch (NumberFormatException nfe) { + System.err.println("Invalid port number, must be integer: " + strPort + "\n"); + printHelp(options); + System.exit(1); + } + + configureLogging(cl.getOptionValue("log-level", "INFO")); + + Component component = new Component(); + Server server = component.getServers().add(Protocol.HTTP, port); + + String conParams; + if (cl.hasOption("connector-params")) { + conParams = cl.getOptionValue("connector-params"); + for (String param : conParams.split(",")) { + if (param.length() > 0) { + String[] kv = param.split("="); + if (kv.length == 2) { + log.debug("Adding connector parameter: {}={}", kv[0], kv[1]); + server.getContext().getParameters().add(kv[0].trim(), kv[1].trim()); + } else { + System.err.println("Invalid connector parameter: " + param); + System.exit(1); + } + } + } + } + + component.getLogService().setResponseLogFormat("{ciua} \"{m} {rp} {rq}\" {S} {ES} {es} {hh} {cig} {fi}"); + server.getContext().getParameters().add("useForwardedForHeader", "true"); + component.getClients().add(Protocol.HTTP); + component.getClients().add(Protocol.HTTPS); + Context c = component.getContext().createChildContext(); + + try { + component.getDefaultHost().attach(new RestApplication(c)); + component.start(); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + + private static void printHelp(Options options) { + HelpFormatter formatter = new HelpFormatter(); + formatter.setWidth(100); + formatter.setLeftPadding(2); + formatter.printHelp("rowstore", options,true); + } + + private static void configureLogging(String logLevel) { + Level l = Level.toLevel(logLevel, Level.INFO); + Configurator.setRootLevel(l); + log.info("Log level set to " + l); + } + + private static void out(String s) { + System.out.println(s); + } + +} diff --git a/standalone/jetty/pom.xml b/standalone/jetty/pom.xml new file mode 100644 index 0000000..fe32249 --- /dev/null +++ b/standalone/jetty/pom.xml @@ -0,0 +1,80 @@ + + + + + 4.0.0 + + se.metasolutions.recruit + rest-standalone + 1.0-SNAPSHOT + + rest-standalone-jetty + jar + 1.0-SNAPSHOT + REST Standalone Jetty + + + + + src/main/resources + + + + + src/test/resources + + **/*.xml + **/*.properties + + + + + + maven-compiler-plugin + + ${maven.compiler.release} + + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + se.metasolutions.recruit.RestApplicationStandaloneJetty + rest + + + flat + true + ${project.build.directory}/dist + + + + + package + + assemble + + + + + + + + + + se.metasolutions.recruit + rest-standalone-common + ${project.version} + + + org.restlet.jse + org.restlet.ext.jetty + ${restlet.version} + + + + diff --git a/standalone/jetty/src/main/java/se/metasolutions/recruit/RestApplicationStandaloneJetty.java b/standalone/jetty/src/main/java/se/metasolutions/recruit/RestApplicationStandaloneJetty.java new file mode 100644 index 0000000..836eedf --- /dev/null +++ b/standalone/jetty/src/main/java/se/metasolutions/recruit/RestApplicationStandaloneJetty.java @@ -0,0 +1,10 @@ +package se.metasolutions.recruit; + +/** + * Main class to start using Jetty. + * + * @author Hannes Ebner + */ +public class RestApplicationStandaloneJetty extends RestApplicationStandalone { + +} diff --git a/standalone/pom.xml b/standalone/pom.xml new file mode 100644 index 0000000..611cc20 --- /dev/null +++ b/standalone/pom.xml @@ -0,0 +1,22 @@ + + + + + 4.0.0 + + se.metasolutions.recruit + rest-parent + 1.0-SNAPSHOT + + rest-standalone + pom + 1.0-SNAPSHOT + REST Standalone + + + common + jetty + + + diff --git a/webapp/pom.xml b/webapp/pom.xml new file mode 100644 index 0000000..5fae654 --- /dev/null +++ b/webapp/pom.xml @@ -0,0 +1,134 @@ + + + 4.0.0 + + rest-webapp + jar + 1.0-SNAPSHOT + REST WebApp + + + se.metasolutions.recruit + rest-parent + 1.0-SNAPSHOT + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-jar-plugin + + + make-a-jar + compile + + jar + + + + + + org.apache.maven.plugins + maven-install-plugin + + + install + + install-file + + + jar + ${project.artifactId} + ${project.groupId} + ${project.version} + ${project.build.directory}/${project.artifactId}-${project.version}.jar + + + + + + + + + + org.restlet.jse + org.restlet + ${restlet.version} + + + org.restlet.jse + org.restlet.ext.json + ${restlet.version} + + + org.restlet.jee + org.restlet.ext.servlet + ${restlet.version} + + + org.restlet.jse + org.restlet.ext.slf4j + ${restlet.version} + + + javax.servlet + javax.servlet-api + ${servlet.version} + provided + + + org.json + json + ${jsonorg.version} + + + commons-logging + commons-logging + 99.0-does-not-exist + + + commons-logging + commons-logging-api + 99.0-does-not-exist + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + com.google.guava + guava + ${guava.version} + + + + diff --git a/webapp/src/main/java/se/metasolutions/recruit/RestApplication.java b/webapp/src/main/java/se/metasolutions/recruit/RestApplication.java new file mode 100644 index 0000000..d02dc76 --- /dev/null +++ b/webapp/src/main/java/se/metasolutions/recruit/RestApplication.java @@ -0,0 +1,135 @@ +package se.metasolutions.recruit; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; +import se.metasolutions.recruit.resources.DefaultResource; +import se.metasolutions.recruit.resources.StatusResource; +import org.json.JSONException; +import org.json.JSONObject; +import org.restlet.Application; +import org.restlet.Context; +import org.restlet.Restlet; +import org.restlet.engine.io.IoUtils; +import org.restlet.routing.Router; +import org.restlet.routing.Template; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Boilerplate for a REST API. + */ +public class RestApplication extends Application { + + static Logger log = LoggerFactory.getLogger(RestApplication.class); + + public static String KEY = RestApplication.class.getCanonicalName(); + + public static String NAME = "REST"; + + private static String VERSION = null; + + public RestApplication(Context parentContext) throws IOException, JSONException { + this(parentContext, null); + } + + public RestApplication(Context parentContext, URI configURI) throws IOException, JSONException { + super(parentContext); + getContext().getAttributes().put(KEY, this); + } + + @Override + public synchronized Restlet createInboundRoot() { + getContext().getParameters().add("useForwardedForHeader", "true"); + + Router router = new Router(getContext()); + router.setDefaultMatchingMode(Template.MODE_EQUALS); + + // global scope + router.attach("/status", StatusResource.class); + router.attach("/", DefaultResource.class); + + return router; + } + + public static String getVersion() { + if (VERSION == null) { + URI versionFile = getConfigurationURI("VERSION.txt"); + try { + log.debug("Reading version number from " + versionFile); + VERSION = readFirstLine(versionFile.toURL()); + } catch (IOException e) { + log.error(e.getMessage()); + } + if (VERSION == null) { + VERSION = new SimpleDateFormat("yyyyMMdd").format(new Date()); + } + } + return VERSION; + } + + public static URI getConfigurationURI(String fileName) { + URL resURL = Thread.currentThread().getContextClassLoader().getResource(fileName); + try { + if (resURL != null) { + return resURL.toURI(); + } + } catch (URISyntaxException e) { + log.error(e.getMessage()); + } + + String classPath = System.getProperty("java.class.path"); + String[] pathElements = classPath.split(System.getProperty("path.separator")); + for (String element : pathElements) { + File newFile = new File(element, fileName); + if (newFile.exists()) { + return newFile.toURI(); + } + } + log.error("Unable to find " + fileName + " in classpath"); + return null; + } + + private void setLogLevel(String logLevel) { + Level l = Level.toLevel(logLevel, Level.INFO); + Configurator.setRootLevel(l); + log.info("Log level set to " + l); + } + + private static String readFirstLine(URL url) { + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(url.openStream())); + return in.readLine(); + } catch (IOException ioe) { + log.error(ioe.getMessage()); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + } + return null; + } + + @Override + public synchronized void stop() throws Exception { + log.info("Shutting down"); + super.stop(); + } + +} diff --git a/webapp/src/main/java/se/metasolutions/recruit/resources/BaseResource.java b/webapp/src/main/java/se/metasolutions/recruit/resources/BaseResource.java new file mode 100644 index 0000000..7a2a4ea --- /dev/null +++ b/webapp/src/main/java/se/metasolutions/recruit/resources/BaseResource.java @@ -0,0 +1,104 @@ +package se.metasolutions.recruit.resources; + +import se.metasolutions.recruit.RestApplication; +import org.restlet.Context; +import org.restlet.Request; +import org.restlet.Response; +import org.restlet.data.MediaType; +import org.restlet.data.ServerInfo; +import org.restlet.resource.ServerResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.HashMap; + +/** + * Base resource from which all other REST resources are subclassed. Handles basic functionality such as parsing of parameters. + */ +public class BaseResource extends ServerResource { + + private static ServerInfo serverInfo; + + protected MediaType format; + + protected HashMap parameters; + + private static Logger log = LoggerFactory.getLogger(BaseResource.class); + + @Override + public void init(Context c, Request request, Response response) { + parameters = parseRequest(request.getResourceRef().getRemainingPart()); + super.init(c, request, response); + + if (parameters.containsKey("format")) { + String format = parameters.get("format"); + if (format != null) { + // workaround for URL-decoded pluses (space) in MIME-type names, e.g. ld+json + format = format.replaceAll(" ", "+"); + this.format = new MediaType(format); + } + } + + // we set a custom Server header in the HTTP response + setServerInfo(this.getServerInfo()); + } + + @Override + protected void doRelease() { + + } + + static public HashMap parseRequest(String request) { + HashMap argsAndVal = new HashMap(); + + int r = request.lastIndexOf("?"); + String req = request.substring(r + 1); + String[] arguments = req.split("&"); + + try { + for (int i = 0; i < arguments.length; i++) { + if (arguments[i].contains("=")) { + String[] elements = arguments[i].split("="); + String key = urlDecode(elements[0]).trim(); + String value = urlDecode(elements[1]).trim(); + if (key.length() > 0) { + argsAndVal.put(key, value); + } + } else { + String key = urlDecode(arguments[i]).trim(); + if (key.length() > 0) { + argsAndVal.put(key, ""); + } + } + } + } catch (IndexOutOfBoundsException e) { + // special case! + argsAndVal.put(req, ""); + } + return argsAndVal; + } + + private static String urlDecode(String input) { + if (input != null) { + try { + return URLDecoder.decode(input, "UTF-8"); + } catch (UnsupportedEncodingException uee) { + log.error(uee.getMessage()); + } + } + return null; + } + + @Override + public ServerInfo getServerInfo() { + if (serverInfo == null) { + ServerInfo si = super.getServerInfo(); + si.setAgent(RestApplication.NAME + "/" + RestApplication.getVersion()); + serverInfo = si; + } + return serverInfo; + } + +} diff --git a/webapp/src/main/java/se/metasolutions/recruit/resources/DefaultResource.java b/webapp/src/main/java/se/metasolutions/recruit/resources/DefaultResource.java new file mode 100644 index 0000000..062f27c --- /dev/null +++ b/webapp/src/main/java/se/metasolutions/recruit/resources/DefaultResource.java @@ -0,0 +1,22 @@ +package se.metasolutions.recruit.resources; + +import org.restlet.data.Status; +import org.restlet.representation.Representation; +import org.restlet.representation.StringRepresentation; +import org.restlet.resource.Get; +import org.restlet.resource.ResourceException; + + +/** + * Fallback if no other REST resource matches. Returns 404. + */ +public class DefaultResource extends BaseResource { + + @Get + public Representation represent() throws ResourceException { + getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND); + String msg = "You made a request against the REST API. There is no resource at this URL."; + return new StringRepresentation(msg); + } + +} diff --git a/webapp/src/main/java/se/metasolutions/recruit/resources/StatusResource.java b/webapp/src/main/java/se/metasolutions/recruit/resources/StatusResource.java new file mode 100644 index 0000000..39aba77 --- /dev/null +++ b/webapp/src/main/java/se/metasolutions/recruit/resources/StatusResource.java @@ -0,0 +1,43 @@ +package se.metasolutions.recruit.resources; + +import se.metasolutions.recruit.RestApplication; +import org.json.JSONException; +import org.json.JSONObject; +import org.restlet.ext.json.JsonRepresentation; +import org.restlet.representation.Representation; +import org.restlet.resource.Get; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.ManagementFactory; + +public class StatusResource extends BaseResource { + + private final static Logger log = LoggerFactory.getLogger(StatusResource.class); + + @Get("json") + public Representation getJvmStatus() throws JSONException { + JSONObject result = new JSONObject(); + result.put("version", RestApplication.getVersion()); + result.put("totalMemory", Runtime.getRuntime().totalMemory()); + result.put("freeMemory", Runtime.getRuntime().freeMemory()); + result.put("maxMemory", Runtime.getRuntime().maxMemory()); + result.put("availableProcessors", Runtime.getRuntime().availableProcessors()); + result.put("totalCommittedMemory", getTotalCommittedMemory()); + result.put("committedHeap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted()); + result.put("totalUsedMemory", getTotalUsedMemory()); + result.put("usedHeap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); + return new JsonRepresentation(result); + } + + long getTotalCommittedMemory() { + return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted() + + ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getCommitted(); + } + + long getTotalUsedMemory() { + return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() + + ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed(); + } + +} diff --git a/webapp/src/main/resources/VERSION.txt b/webapp/src/main/resources/VERSION.txt new file mode 100644 index 0000000..730d79a --- /dev/null +++ b/webapp/src/main/resources/VERSION.txt @@ -0,0 +1 @@ +1.0-SNAPSHOT diff --git a/webapp/src/main/resources/log4j2.properties b/webapp/src/main/resources/log4j2.properties new file mode 100644 index 0000000..09e115e --- /dev/null +++ b/webapp/src/main/resources/log4j2.properties @@ -0,0 +1,14 @@ +name = PropertiesConfig +appenders = console + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %replace{%msg}{\r?\n}{\u21B5}%n + +rootLogger.level = INFO +rootLogger.appenderRefs = stdout +rootLogger.appenderRef.stdout.ref = STDOUT + +logger.jetty.name = org.eclipse.jetty +logger.jetty.level = INFO \ No newline at end of file