Skip to content

Conversation

@jglick
Copy link
Member

@jglick jglick commented Nov 8, 2018

JENKINS-54128 Some plugins apparently call this a lot so deal with it.

@jglick jglick requested review from dwnusbaum and svanoort November 8, 2018 03:11
Copy link
Member

@dwnusbaum dwnusbaum left a comment

Choose a reason for hiding this comment

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

Looks good, just minor comments.

}

@Override public File getLogFile() {
LOGGER.log(Level.WARNING, "Avoid calling getLogFile on " + this, new UnsupportedOperationException());
Copy link
Member

Choose a reason for hiding this comment

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

Given the number of existing callers, should we only log the stack trace at FINE level?

Copy link
Member Author

Choose a reason for hiding this comment

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

Well…we only know about those callers because it is at WARNING. And this would be important e.g. for getting sentry.io to show violations in Evergreen.

Copy link
Member

Choose a reason for hiding this comment

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

Isn't this potentially going to generate a log of logspam though?

Copy link
Member

Choose a reason for hiding this comment

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

Also, I don't see that (at least on current Jenkins master branch) that Run.getLogFile is deprecated, which makes it feel very odd to me that we're deprecated its override in WorkflowJob

Copy link
Member Author

Choose a reason for hiding this comment

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

Isn't this potentially going to generate a log of logspam though?

Potentially. Note that the log call code was already there—not touched by this PR.

I don't see that (at least on current Jenkins master branch) that Run.getLogFile is deprecated

Yup, on my to-do list.

Copy link
Member

Choose a reason for hiding this comment

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

Why? While it may be satisfying to simple signal "stop using this API" by making it log a warning every time, for a user this looks like the Workflow Job plugin was broken by the update that added the logging - we've seen this before with "cosmetic" log warnings. Just not great optics or user experience.

Being able to point to deprecation of the extension point in core and an appropriate waiting period gives us more of a leg to stand on here.

Copy link
Member

@timja timja Nov 23, 2018

Choose a reason for hiding this comment

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

so what do I call instead?
I'm making changes to the build-failure-analyzer plugin, and saw my logs being spammed here.
but there's no javadoc explaining what the replacement / another solution is?

It does look removeable as a whole potentially as all it does is get a file name off it but not sure the full implications

https://github.com/hmcts/build-failure-analyzer-plugin/blob/6176af08f11355b427a1db1a1c44c66dafe3de02/src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/BuildLogFailureReader.java#L66

Copy link
Member Author

Choose a reason for hiding this comment

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

@timja Any log-related methods other than getLogFile. getLogText is the basic one. In your case I would suggest simply

-String currentFile = build.getLogFile().getName();
+String currentFile = "log";

Copy link
Member

Choose a reason for hiding this comment

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

Will give it a go later on thanks 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't see that (at least on current Jenkins master branch) that Run.getLogFile is deprecated

jenkinsci/jenkins#3963

Co-Authored-By: jglick <jglick@cloudbees.com>
@dwnusbaum
Copy link
Member

dwnusbaum commented Nov 8, 2018

The only other thing that came to mind while looking at this is that using the same file for non-FileLogStorage implementations seems like it could lead to strange bugs in the face of concurrent calls to getLogFile because the file could be overwritten while another thread is reading from it, but I couldn't really think of any better way to handle that.

} else {
// Some other storage. Cache under the traditional name, but load from the defined source on each call.
try {
f.deleteOnExit();
Copy link
Member

@svanoort svanoort Nov 8, 2018

Choose a reason for hiding this comment

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

Hey, isn't f potentially the original log file, not a "deprecated" temp file that we're copying to/from?

Copy link
Member

Choose a reason for hiding this comment

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

Which means we'd... delete the build log on exit? Unless there's something I missed here?

Copy link
Member Author

Choose a reason for hiding this comment

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

That would be the FileLogStorage branch. I.e., what is run if you do not have the CloudWatch Logs plugin installed.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, but in that case... isn't that the actual build log?

Copy link
Member

Choose a reason for hiding this comment

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

Gotta say it: we really, really, really should have a testcase covering these scenarios. Relying on code review alone to catch issues here is not a longterm path for success.

Copy link
Member Author

Choose a reason for hiding this comment

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

In the case of FileLogStorage, yes that is the actual build log, as it would be for freestyle builds.

Copy link
Member

Choose a reason for hiding this comment

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

🐛 So we're marking for Jenkins to... delete our build's actual logfile on exit. 🐛

Copy link
Member

Choose a reason for hiding this comment

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

Ah, except... due to magic the legacy logs magically have become a FileLogStorage due to the other weirdness of the LogStorage.of call. Which raises the question: what is this code addressing?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unless some plugin adds an alternative, FileLogStorage is in use. It does not matter if this build predates JEP-210.

try (OutputStream os = new FileOutputStream(f)) {
getLogText().writeRawLogTo(0, os);
File f = super.getLogFile();
if (LogStorage.of(asFlowExecutionOwner()) instanceof FileLogStorage) {
Copy link
Member

Choose a reason for hiding this comment

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

Is there a more direct way to accomplish this, by any chance? It seems like it's going to carry a fair bit of logic along with that invocation, i.e. some extra risk -- and IIUC won't https://github.com/jenkinsci/workflow-api-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/log/LogStorage.java#L127 result in it returning a FileLogStorage even if there's no index file associated (i.e. non-rewrite builds)?

Copy link
Member

Choose a reason for hiding this comment

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

Note that this might be an escape hatch for us.

Copy link
Member Author

Choose a reason for hiding this comment

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

returning a FileLogStorage even if there's no index file associated

Yup, and that is right. If there is no index file, log can still be read for the whole-log build. You will not get annotations about which lines came from particular steps, that is all.

Copy link
Member

Choose a reason for hiding this comment

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

I'll put it this way: that feels like an extremely surprising outcome for someone interacting with that API.

Copy link
Member Author

Choose a reason for hiding this comment

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

You should not be interacting with this API at all—it is deprecated—but if you do, it behaves exactly as it did before, and continues to do for freestyle builds: gives you a File containing the complete raw text (i.e., including encoded ConsoleNotes) of the build log.

Copy link
Member

Choose a reason for hiding this comment

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

I mean specifically the LogStorage.of API - agree that in an ideal world nobody would be trying to work with the file directly (although I bet it's still happening anyway)

Copy link
Member

@svanoort svanoort left a comment

Choose a reason for hiding this comment

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

This really, really feels like it's missing testcases to cover both post logging-rewrite logfile and pre-rewrite logfile handling -- specifically making sure they don't get duplicated or removed on shutdown.

@jglick
Copy link
Member Author

jglick commented Nov 8, 2018

concurrent calls to getLogFile

Yes, but the alternative would be the absence of this PR and a separate file per call, which is much worse than any such issue.

If you are a nondefault log storage, you really want to treat all calls to getLogFile as bugs and have them fixed, so any implementation is a best effort.

if (LogStorage.of(asFlowExecutionOwner()) instanceof FileLogStorage) {
// FileLogStorage does write a file with the same name and the same format as before JEP-210, so accept it if it is there.
} else {
// Some other storage. Cache under the traditional name, but load from the defined source on each call.
Copy link
Member

Choose a reason for hiding this comment

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

Question for @jglick - can you please enumerate in code comments which of these cases are meant to handle:

  1. Traditional log storage on-master
  2. The new log-rewrite log storage on-master
  3. Cloud storage on-master

And I feel like we may actually be making a mistake by handing responsibility for those to the WorkflowJob or indeed the Job - it feels like the LogStorage itself ought to take ownership for these (including tests for each case).

Copy link
Member Author

Choose a reason for hiding this comment

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

can you please enumerate in code comments which of these cases are meant to handle

I already did, but I can try to reword the comments.

  • Traditional log storage on-master
  • The new log-rewrite log storage on-master

There is no difference between these two so far as the log file is concerned.

3. Cloud storage on-master

There is no such thing.

the LogStorage itself ought to take ownership for these

No. LogStorage handles writes to, and read from, logs wherever they may be stored, and defines the API for making that pluggable. Legacy code which presumes that the log is a file on the master has to be accommodated somehow, for compatibility.

Copy link
Member

Choose a reason for hiding this comment

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

There is no such thing.

Heh, typing fast, but you know what I meant. :)

No. LogStorage handles writes to, and read from, logs wherever they may be stored, and defines the API for making that pluggable

Per this: https://github.com/jenkinsci/jep/blob/master/jep/207/README.adoc#run-api-compatibility isn't the LogStorage method File toLogFile() supposed to be able to handle all of this?

What, concretely, is the else case addressing here? IIUC unless a key part was left un-implemented we might be able to remove most of this logic.

Copy link
Member

Choose a reason for hiding this comment

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

And if there is a concrete case that we know the 'else' branch is covering, where is its testcase?

Copy link
Member Author

Choose a reason for hiding this comment

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

JEP-207 is only implemented in an experimental branch and I did not propose that API.

The else case will be active when you run the pipeline-log-fluentd-cloudwatch plugin.

dwnusbaum
dwnusbaum previously approved these changes Nov 9, 2018
// Inefficient but probably rarely used anyway.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeLogTo(getLogText()::writeLogTo, baos);
writeLogTo(getLogText()::writeRawLogTo, baos);
Copy link
Member

Choose a reason for hiding this comment

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

Yikes, caused by my changes in #114. Good catch!

Copy link
Member

@svanoort svanoort left a comment

Choose a reason for hiding this comment

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

This is much cleaner and feels safer & more maintainable. I'm not going to quibble more about the deprecation exceptions for now (we'll see how often those come).

@jglick
Copy link
Member Author

jglick commented Nov 9, 2018

the deprecation exceptions

I am certainly open to changes in logging, but this is really a separate topic. Ideally I would like to have something in Jenkins consolidate similar warnings—like a custom log handler in Winstone?

@dwnusbaum dwnusbaum merged commit 779112f into jenkinsci:master Nov 9, 2018
@jglick jglick deleted the JENKINS-54128 branch November 9, 2018 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants