-
Notifications
You must be signed in to change notification settings - Fork 33
Changes from 109 commits
e748691
f6d1488
2ad99b0
30b3e80
7ec8ff3
1d3ca8a
3b5c3a7
aa81e13
141bae3
48df809
1e38c88
f19135d
4a0886e
df430d6
fe02767
2005182
3d2baec
563140f
3206abf
9de4fc1
f884043
9ea5c97
abc7b09
9318aa1
2dc88d0
d50f5ae
9e5e2db
c6d8df8
d5f5613
9a22c3d
4f738b7
34e9103
f255ee1
fc0ed8d
24a9055
9182d7e
688ed8e
b4d7add
d3e5d9d
06b1a2e
9f64c08
8fb26f2
22e7518
e7a8fcb
4032481
80ee54e
4835abc
f1e55dc
64a0a20
cb4b5f8
cb852d3
f3ef369
72636e8
912d09d
eb6eddb
1976930
2c022d7
cd8bdf8
6ad4bd8
9080fc7
63d986d
cda775a
57613d6
edc450d
c1225ec
1c4c5a9
3a2bfa9
1fc1244
974bb28
7a76e45
c58bbaf
c3d5f0d
17e3af9
87cf4ae
8ea1238
4766ae5
aafc67a
441a3fb
0def22a
81014f6
90ca817
bdad80a
d9a19a9
bc4d478
3240d37
0fc1215
42ba89c
1c73bb6
21fe0cd
151d496
a7e7f37
5a57c6d
d1d9a47
86f8154
e75419d
3f32e54
37f5bd4
4754bc4
8615410
115759a
aa91b0b
91a62d8
2f7dc9c
ac00fd1
187cac8
376481f
4b80727
ae6b9ce
21404d7
de07ed9
df47a07
bfc9e45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,8 +92,8 @@ Additional environment variables are used/set including: | |
|`JETTY_BASE` |`jetty.base` |`/var/lib/jetty` | | ||
|`TMPDIR` | |`/tmp/jetty` | | ||
|`JETTY_PROPERTIES`| |Comma separated list of `name=value` pairs appended to `$JETTY_ARGS` | | ||
|`JETTY_MODULES_ENABLED`| |Comma separated list of modules to enable by appending to `$JETTY_ARGS` | | ||
|`JETTY_MODULES_DISABLED`| |Comma separated list of modules to disable by removing from `$JETTY_BASE/start.d` | | ||
|`JETTY_MODULES_ENABLE`| |Comma separated list of modules to enable by appending to `$JETTY_ARGS` | | ||
|`JETTY_MODULES_DISABLE`| |Comma separated list of modules to disable by removing from `$JETTY_BASE/start.d` | | ||
|`JETTY_ARGS` | |`-Djetty.base=$JETTY_BASE -jar $JETTY_HOME/start.jar` | | ||
|`ROOT_WAR` | |`$JETTY_BASE/webapps/root.war` | | ||
|`ROOT_DIR` | |`$JETTY_BASE/webapps/root` | | ||
|
@@ -112,15 +112,88 @@ java $JAVA_OPTS \ | |
-jar $JETTY_HOME/start.jar \ | ||
"$@" | ||
``` | ||
## Logging | ||
This image is configured to use [Java Util Logging](https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html)(JUL) to capture all logging from | ||
the container and its dependencies. Applications that also use the JUL API will inherit the same logging configuration. | ||
|
||
The configuration of the jetty container in this image can be viewed by running the image locally: | ||
By default JUL is configured to use a [ConsoleHandler](https://docs.oracle.com/javase/8/docs/api/java/util/logging/ConsoleHandler.html) to send logs to the `stderr` of the container process. When run on as a GCP deployment, all output to `stderr` is captured and is available via the Stackdriver logging console, however more detailed and integrated logs are available if the Stackdriver logging mechanism is used directly (see below). | ||
|
||
To alter logging configuration a new `logging.properties` file must be provided to the image that among other things can: alter log levels generated by Loggers; alter log levels accepted by handlers; add/remove/configure log handlers. | ||
|
||
|
||
### Providing `logging.properties` via the web application | ||
A new logging configuration file can be provided as part of the application (typically at `WEB-INF/logging.properties`) | ||
and the Java System Property `java.util.logging.config.file` updated to reference it. | ||
|
||
When running in a GCP environment, the system property can be set in `app.yaml`: | ||
```yaml | ||
env_variables: | ||
JAVA_USER_OPTS: -Djava.util.logging.config.file=WEB-INF/logging.properties | ||
``` | ||
docker run --rm -it launcher.gcr.io/google/jetty --list-config --list-modules | ||
|
||
If the image is run directly, then a `-e` argument to the `docker run` command can be used to set the system property: | ||
|
||
```bash | ||
docker run \ | ||
-e JAVA_USER_OPTS=-Djava.util.logging.config.file=WEB-INF/logging.properties \ | ||
... | ||
``` | ||
|
||
### Providing `logging.properties` via a custom image | ||
If this image is being used as the base of a custom image, then the following `Dockerfile` commands can be used to add either replace the existing logging configuration file or to add a new `logging.properties` file. | ||
|
||
The default logging configuration file is located at `/var/lib/jetty/etc/java-util-logging.properties`, which can be replaced in a custom image is built. The default configuration can be replaced with a `Dockerfile` like: | ||
|
||
```Dockerfile | ||
FROM gcr.io/google-appengine/jetty | ||
ADD logging.properties /var/lib/jetty/etc/java-util-logging.properties | ||
... | ||
``` | ||
|
||
Alternately an entirely new location for the file can be provided and the environment amended in a `Dockerfile` like: | ||
|
||
```Dockerfile | ||
FROM gcr.io/google-appengine/jetty | ||
ADD logging.properties /etc/logging.properties | ||
ENV JAVA_USER_OPTS -Djava.util.logging.config.file=/etc/logging.properties | ||
... | ||
``` | ||
|
||
### Providing `logging.properties` via docker run | ||
A `logging.properties` file may be added to an existing images using the `docker run` command if the deployment environment allows for the run arguments to be modified. The `-v` option can be used to bind a new `logging.properties` file to the running instance and the `-e` option can be used to set the system property to point to it: | ||
```shell | ||
docker run -it --rm \ | ||
-v /mylocaldir/logging.properties:/etc/logging.properties \ | ||
-e JAVA_USER_OPTS="-Djava.util.logging.config.file=/etc/logging.properties" \ | ||
... | ||
``` | ||
|
||
### Enhanced Stackdriver Logging (BETA!) | ||
When running on the Google Cloud Platform Flex environment, the Java Util Logging can be configured to send logs to Google Stackdriver Logging by providing a `logging.properties` file that configures a [LoggingHandler](http://googlecloudplatform.github.io/google-cloud-java/0.10.0/apidocs/com/google/cloud/logging/LoggingHandler.html) as follows: | ||
``` | ||
.level=INFO | ||
io.grpc.netty.level=INFO | ||
sun.net.level=INFO | ||
|
||
handlers=com.google.cloud.logging.LoggingHandler | ||
com.google.cloud.logging.LoggingHandler.level=FINE | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be removed before merging? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. This just says it will log any FINE entries that are generated, but the line 140 sets the default generation to just be INFO. By leaving the FINE in the handler it means that you only need to change the level in one place. In fact there is an argument to change it to FINEST |
||
com.google.cloud.logging.LoggingHandler.log=gae_app.log | ||
com.google.cloud.logging.LoggingHandler.resourceType=gae_app | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't you need to provide more config here?
|
||
com.google.cloud.logging.LoggingHandler.enhancers=com.google.cloud.logging.GaeFlexLoggingEnhancer | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is running on GAE Flex, you no longer need to specify the resourceType and enhancers. it gets auto-detected based on the GAE_INSTANCE env var. TraceLoggingEnhancer is automatically added. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great! Thanks Jisha! |
||
com.google.cloud.logging.LoggingHandler.formatter=java.util.logging.SimpleFormatter | ||
java.util.logging.SimpleFormatter.format=%3$s: %5$s%6$s | ||
|
||
``` | ||
This uses the [GaeFlexLoggingEnhancer](http://googlecloudplatform.github.io/google-cloud-java/0.10.0/apidocs/com/google/cloud/logging/GaeFlexLoggingEnhancer.html) to enhances the logs generated be linking them to the `nginx` request log in the logging console by `traceid` (The traceId for a request on a Google Cloud Platform is obtained from the `setCurrentTraceId` HTTP header as the first field of the `'/'` delimited value). | ||
|
||
When an image so configured is deployed on a GCP environment, then the `gcp` module will automatically call the [setCurrentTraceId](http://googlecloudplatform.github.io/google-cloud-java/0.10.0/apidocs/com/google/cloud/logging/GaeFlexLoggingEnhancer.html#setCurrentTraceId-java.lang.String-) for any thread handling a request. | ||
|
||
When using Stackdriver logging, it is recommended that `io.grpc` and `sun.net` logging level is kept at INFO level, as both these packages are used by Stackdriver internals and can result in verbose and/or initialisation problems. | ||
|
||
|
||
## Extending the image | ||
The image produced by this project may be automatically used/extended by the Cloud SDK and/or App Engine maven plugin. | ||
Alternately it may be explicitly extended with a custom Dockerfile. | ||
Alternately it may be explicitly extended with a custom Dockerfile. | ||
|
||
The latest released version of this image is available at `launcher.gcr.io/google/jetty`, alternately you may | ||
build and push your own version with the shell commands: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright (C) 2016 Google Inc. | ||
* | ||
* Licensed 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 com.google.cloud.runtimes.jetty9; | ||
|
||
import com.google.cloud.logging.TraceLoggingEnhancer; | ||
|
||
import org.eclipse.jetty.server.Request; | ||
import org.eclipse.jetty.server.handler.ContextHandler; | ||
import org.eclipse.jetty.server.handler.ContextHandler.Context; | ||
import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener; | ||
|
||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
/** | ||
* A Jetty {@link ContextScopeListener} that is called whenever | ||
* a container managed thread enters or exits the scope of a context and/or request. | ||
* Used to maintain {@link ThreadLocal} references to the current request and | ||
* Google traceID, primarily for logging. | ||
* @see TracingLogHandler | ||
*/ | ||
public class RequestContextScope implements ContextHandler.ContextScopeListener { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add some javadocs to explain the purpose of the class? |
||
static final Logger logger = Logger.getLogger(RequestContextScope.class.getName()); | ||
|
||
private static final String X_CLOUD_TRACE = "x-cloud-trace-context"; | ||
private static final ThreadLocal<Integer> contextDepth = new ThreadLocal<>(); | ||
|
||
@Override | ||
public void enterScope(Context context, Request request, Object reason) { | ||
if (logger.isLoggable(Level.FINE)) { | ||
logger.fine("enterScope " + context); | ||
} | ||
if (request != null) { | ||
Integer depth = contextDepth.get(); | ||
if (depth == null || depth.intValue() == 0) { | ||
depth = 1; | ||
String traceId = (String) request.getAttribute(X_CLOUD_TRACE); | ||
if (traceId == null) { | ||
traceId = request.getHeader(X_CLOUD_TRACE); | ||
if (traceId != null) { | ||
int slash = traceId.indexOf('/'); | ||
if (slash >= 0) { | ||
traceId = traceId.substring(0, slash); | ||
} | ||
request.setAttribute(X_CLOUD_TRACE, traceId); | ||
TraceLoggingEnhancer.setCurrentTraceId(traceId); | ||
} | ||
} else { | ||
depth = depth + 1; | ||
} | ||
contextDepth.set(depth); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void exitScope(Context context, Request request) { | ||
if (logger.isLoggable(Level.FINE)) { | ||
logger.fine("exitScope " + context); | ||
} | ||
Integer depth = contextDepth.get(); | ||
if (depth != null) { | ||
if (depth > 1) { | ||
contextDepth.set(depth - 1); | ||
} else { | ||
contextDepth.remove(); | ||
TraceLoggingEnhancer.setCurrentTraceId(null); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
--create-startd | ||
|
||
--add-to-start=server,webapp,http,deploy,jsp,jstl,resources | ||
--approve-all-licenses | ||
--add-to-start=server,webapp,http,deploy,jsp,jstl,resources,logging-jul,jcl-slf4j | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.level=INFO | ||
|
||
handlers=java.util.logging.ConsoleHandler | ||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter | ||
java.util.logging.SimpleFormatter.format=%3$s: %5$s%6$s%n | ||
|
||
## To use Stackdriver Logging replace the configuration above with the configuration below: | ||
# handlers=com.google.cloud.logging.LoggingHandler | ||
# com.google.cloud.logging.LoggingHandler.level=FINE | ||
# com.google.cloud.logging.LoggingHandler.log=gae_app.log | ||
# com.google.cloud.logging.LoggingHandler.resourceType=gae_app | ||
# com.google.cloud.logging.LoggingHandler.enhancers=com.google.cloud.logging.GaeFlexLoggingEnhancer | ||
# com.google.cloud.logging.LoggingHandler.formatter=java.util.logging.SimpleFormatter | ||
# java.util.logging.SimpleFormatter.format=%3$s: %5$s%6$s |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright (C) 2016 Google Inc. | ||
* | ||
* Licensed 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 com.google.cloud.runtimes.jetty9; | ||
|
||
import java.io.IOException; | ||
import java.util.logging.Logger; | ||
|
||
import javax.annotation.PostConstruct; | ||
import javax.servlet.ServletException; | ||
import javax.servlet.annotation.WebServlet; | ||
import javax.servlet.http.HttpServlet; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
|
||
@SuppressWarnings("serial") | ||
@WebServlet(urlPatterns = {"/", "/test/*"}, name = "TestServlet") | ||
public class TestServlet extends HttpServlet { | ||
static final Logger log = Logger.getLogger(TestServlet.class.getName()); | ||
|
||
@PostConstruct | ||
private void myPostConstructMethod() { | ||
log.info("preconstructed"); | ||
} | ||
|
||
@Override | ||
public void init() throws ServletException { | ||
log.info("init info"); | ||
getServletContext().log("init ServletContext.log"); | ||
} | ||
|
||
@Override | ||
public void doGet(HttpServletRequest request, HttpServletResponse response) | ||
throws ServletException, IOException { | ||
log.info("doGet info"); | ||
getServletContext().log("doGet ServletContext.log"); | ||
|
||
if (request.getParameter("ex") != null) { | ||
try { | ||
throw (Throwable) Class.forName(request.getParameter("ex")).newInstance(); | ||
} catch (ServletException | IOException ex) { | ||
throw ex; | ||
} catch (Throwable th) { | ||
throw new ServletException(th); | ||
} | ||
} | ||
response.getWriter().println("Log Test"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to enable this handler conditionally based on environment in which the container is running. For example, it won't work locally.