Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.

Issue #333 Async FileHandler#334

Merged
gregw merged 3 commits intoasync-supportfrom
async-support-333
Nov 22, 2016
Merged

Issue #333 Async FileHandler#334
gregw merged 3 commits intoasync-supportfrom
async-support-333

Conversation

@gregw
Copy link
Contributor

@gregw gregw commented Nov 18, 2016

No description provided.

public void close() throws SecurityException {
super.close();
if (handlers.decrementAndGet() <= 0 ) {
queue.offer(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this? Wouldn't it just cause a NullPointerException?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

offer(null) is just a poison pill for the LoggerThread

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like BlockingQueue allows adding null at all:
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html#offer(E)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so much for testing! Anyway, null is a poor poison pill! I'll make a specific LogEvent instance that is the poison pill.

@Override
public void publish(LogRecord record) {
if (isLoggable(record)) {
queue.offer(new LogEntry(record));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the return value of offer() be checked?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a return of false from .offer() means the queue is full.
knowing that, what would you do in that situation? (how would you handle false?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I have gone with an unlimited log queue. If you look at the Juli example linked to, you will see that they have a fixed sized queue with configurable actions to do if the queue is full (discard, block etc.).

My thoughts on this is that any app that is suffering OOM issues because of a large logevent queue is probably going to have similar issues anyway, even if the logevents are discarded. I think an unlimited queue is thus the simplest and does not need configuration and/or tuning.

So if the unlimited policy is accepted, the offer return does not need to be checked. However I'm open to be convinced that another policy may be better?

super.publish(record);
}

private class LogEntry {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for introducing this class? Can the queue simply hold LogRecords directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LogEntry class is a nest class and thus holds a reference back to the handler instance that created it. Multiple handler instances can exist and they share the queue and thread. The async thread when doing the actual logging calls back to the handler instance.

This design is copied from the Juli log. It may not be necessary as we "know" that there should only be a single instance of the handler.

The other option is to have a none static queue and thread, so that every instance of the handler would create their own queue. This would not be an issue as we only create 1, but would at least work if more were created.

assertThat(data.severity, equalTo("ERROR"));
assertThat(
data.message, org.hamcrest.Matchers.containsString("LoggingServlet doGet: not null"));
data.message, org.hamcrest.Matchers.containsString("com.foo.bar: not null"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What accounts for this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good question. I don't actually know how that test was passing before because the logs are explicitly generated from a "com.foo.bar" logger.

So I'll take this question on notice and research how it was working prior to this PR.

Copy link

@joakime joakime Nov 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old jetty9-compat logging didn't log with the logger name, it used "<calling class> <calling method name>: <message>" (I know, its strange, but that's what they did)

@gregw
Copy link
Contributor Author

gregw commented Nov 22, 2016

@meltsufin I have pushed a simplification of the async logging. However I note that the JsonFormatter is using the current thread to set the thread field in the log record. This is now always the async logging thread.

Thus we either need to not bother logging the thread, or add a mechanism to capture the logging thread and use that (may need a LogEvent class again). Your thoughts?

@gregw
Copy link
Contributor Author

gregw commented Nov 22, 2016

Ah the LogRecord already has the integer thread ID, so the JsonFormatter should just use that rather than the current thread.

@meltsufin
Copy link
Member

Thread name is not quiet the same as thread id, and can also be useful in debugging. However, looking at the Log Viewer, it doesn't seem to be parsed out from the JSON anyway. So, I'm tempted to just remove it.

@gregw
Copy link
Contributor Author

gregw commented Nov 22, 2016

@meltsufin note that for compat, the log is still created as a file on disk, so having some thread identifier there may still be useful in debugging, as at least it can be found. Thus I'm inclined to leave as is.

I'll review how thread is being treated in the jetty-runtime stuff, but I think it is fine as it is only the write that is happening async, not the format.

@meltsufin
Copy link
Member

Sounds good. LGTM

@gregw gregw merged commit 79cf4fa into async-support Nov 22, 2016
@meltsufin meltsufin deleted the async-support-333 branch November 22, 2016 21:53
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants