Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid mutating global STDOUT & STDERR #1837

Merged
merged 2 commits into from Jul 25, 2019
Merged

Conversation

montanalow
Copy link
Contributor

The current behavior prevents apps from benefitting from STDOUT.sync = false during configuration phases, since the initial call to Event.stdio is relatively late in the boot cycle.

@nateberkopec
Copy link
Member

I'm afraid I don't understand the use case.

This PR mostly changes how our internal logs interact with flush. This seems weird, first of all, because the whole point of sync = false is, IMO, to let Ruby do the flushing for you.

I also don't understand the PR title - how was global stdout and stderr being modified before this PR?

@nateberkopec nateberkopec added the waiting-for-changes Waiting on changes from the requestor label Jul 16, 2019
@montanalow
Copy link
Contributor Author

montanalow commented Jul 17, 2019

$stdout = STDOUT by default.

This call results in setting $stdout.sync = true.
https://github.com/puma/puma/blob/master/lib/puma/events.rb#L145

In the current code path, whenever Puma::Events.stdio is called, STDOUT & STDERR will be changed to sync. sync is not the default behavior for STDOUT & STDERR so this is a side effect on a global variable that will have application wide results.

I would like to prevent this side effect, so Puma applications can run with STDOUT.sync # => false

I'm unfamiliar with the reasoning behind the current code setting sync = true, but my patch preserves the behavior of synchronized output for Events, by flushing stdout and stderr any time output is written.

@nateberkopec nateberkopec removed the waiting-for-changes Waiting on changes from the requestor label Jul 17, 2019
@nateberkopec
Copy link
Member

Why not just change the default IO to a new STDOUT/STDERR object, then?

E.g.

def self.stdio
    Events.new $stdout.dup, $stderr.dup
end

@nateberkopec
Copy link
Member

nateberkopec commented Jul 17, 2019

That leaves the separate issue of us forcing you to use sync = true, but at least we avoid the global side effect.

@nateberkopec
Copy link
Member

nateberkopec commented Jul 17, 2019

Actually, even better:

def self.stdio 
    stdout = $stdout.dup
    stdout.sync = false 
    stderr = $stderr.dup 
    stderr.sync = false
    Events.new stdout, stderr
end

then rm the sync code from Events#initialize

@montanalow
Copy link
Contributor Author

@nateberkopec To catch DEFAULT = new(STDOUT, STDERR) as well, I moved the dup inside initialize, which I think aligns with your suggestions.

@nateberkopec
Copy link
Member

I think that's OK, but you'll need to make sure that the rack handler changes it's arguments so that the correct item is used.

@montanalow
Copy link
Contributor Author

Not sure I follow, are you worried about the resulting StringIO.new.dup from Rack::Events.strings?

@nateberkopec
Copy link
Member

On that line, ::Puma::Events.stdio (which is the code path we'll take if the the silent option is NOT present) will return the global stdout/stderr. That is then passed into Puma::Launcher#new, avoiding the change that you've made here b/c the event is passed in explicitly.

@montanalow
Copy link
Contributor Author

Sorry if I'm still missing something, but I thought that's what my change would address. By duping the args from all callers inside Events#intitialize, before sync is set, there shouldn't be any way to get update the globals, even if you pass them in.

Events.stdio will be dupped, so won't impact $stdout, and Events::DEFAULT will also be dupped to avoid mutating STDOUT, when called from Puma::Launcher#initialize here https://github.com/puma/puma/blob/master/lib/puma/launcher.rb#L48

@nateberkopec
Copy link
Member

Well, write a test and we'll find out then 😆 You'll have to fix the tests that are looking for output at $stdout/$stderr too unfortunately.

@nateberkopec
Copy link
Member

Looking at this again and I think you're probably write, but it does need new tests + fixes of the old ones for a merge.

@nateberkopec nateberkopec removed the waiting-for-changes Waiting on changes from the requestor label Jul 22, 2019
@nateberkopec nateberkopec merged commit 70b28bb into puma:master Jul 25, 2019
@nateberkopec
Copy link
Member

Thanks for all your work @montanalow !

Jesus pushed a commit to Jesus/puma that referenced this pull request Jul 25, 2019
MSP-Greg added a commit to MSP-Greg/puma that referenced this pull request Aug 19, 2019
MSP-Greg added a commit to MSP-Greg/puma that referenced this pull request Aug 19, 2019
@nateberkopec
Copy link
Member

Who could have guessed the entire Puma logging ecosystem somehow depended on us modifying STDOUT.sync to true... a good lesson for software maintainership - modifying a global is probably worth a major version bump!

nateberkopec added a commit that referenced this pull request Sep 2, 2019
nateberkopec added a commit that referenced this pull request Sep 2, 2019
nateberkopec added a commit that referenced this pull request Sep 5, 2019
nateberkopec added a commit that referenced this pull request Sep 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants