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

log link to speedscope during gcs upload #47

Merged
merged 1 commit into from
May 25, 2022
Merged

Conversation

kimbilida
Copy link
Contributor

Why?

Make it easier to link to the flamegraph in speedscope. When trying to get to the profile I needed to read through the docs and then eventually disturb @dalehamel to get the right link.

How?

  • Always output the link to AppProfiler.speedscope_host instead of just the gcs location to make it easier to get to the flame graph and to avoid having to read through the docs
  • pulled the link logic that was in the middleware/upload_action into the app_profiler and accessed the method from profile

Next: can remove the logging from the background queue in core

For reviewers:

  • other suggested approaches?

Copy link
Member

@dalehamel dalehamel left a comment

Choose a reason for hiding this comment

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

I think that this functionality already will basically depend on the url formatter being set to provide useful output, as the default case generates (and apparently, always has) a nonsense URL. For this reason, I'm suggesting simplifying the PR a bit and just checking if the formatter is defined, and if so, call it, leaving the current profile_url method where it is.

Overall this does look like it will achieve what it sets out to, and make it easier to get the profile URL by relying on the custom formatter being set by the app.

I'd like to defer to @gmcgibbon though as he's a better rubyist than myself and is familiar with this gem. Before rewriting anything, let's hear what he has to say.


def profile_url(upload)
if AppProfiler.profile_url_formatter.nil?
"#{AppProfiler.speedscope_host}#profileURL=#{upload.url}"
Copy link
Member

Choose a reason for hiding this comment

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

As I mentioned on slack, I think this branch path can be misleading, it is likely it will generate URLs that do not work (but this code was already here since the initial import and I guess that was just missed). We more or less require that the profile formatter be given to generate the correct URL, as I am pretty sure this default one will fail in almost every situation.

I think I'd opt for leaving this code where it is, tucked in the middleware module, and then just directly call the formatter if it is defined, since I'd argue the default case here has essentially no value, perhaps even negative value as it will generate wrong URLs.

Copy link
Member

@gmcgibbon gmcgibbon May 19, 2022

Choose a reason for hiding this comment

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

This is for the default case of using a local speedscope instance and filesystem storage. I would prefer if we just made this the default profile_url_formatter proc eg. mattr_accessor :profile_url_formatter, default: proc { |upload| "#{AppProfiler.speedscope_host}#profileURL=#{upload.url}" }. This way there are no conditionals.

Copy link
Member

@dalehamel dalehamel May 19, 2022

Choose a reason for hiding this comment

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

@gmcgibbon ah! that makes sense, i hadn't considered that it would work with a local file and speedscope instance! Thanks for clarifying 👍

@@ -41,6 +41,7 @@ def upload
AppProfiler.storage.upload(self).tap do |upload|
if upload && defined?(upload.url)
AppProfiler.logger.info("[Profiler] uploaded profile profile_url=#{upload.url}")
AppProfiler.logger.info("[Profiler] Profile available at profile_url=#{AppProfiler.profile_url(upload)}")
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if a better approach would be to do the following:

unless AppProfiler.profile_url_formatter.nil?
  AppProfiler.logger.info("[Profiler] Profile available at profile_url=#{AppProfiler.profile_url_formatter.call(upload)}")
end

Then add a new test like assert_custom_url_printed_on_upload that sets the url formatter and checks the output as you have in your existing test.

Copy link
Member

Choose a reason for hiding this comment

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

I think we're talking about 2 different things in this log message. The profile_url (the location of the profile on the storage service) and the speedscope_url (the address to actually view the profile). I think this would make more sense:

AppProfiler.logger.info("[Profiler] uploaded profile profile_url=#{upload.url} speedscope_url=#{AppProfiler.profile_url_formatter.call(upload)}")

It would be nice if we could define #speedscope_url on the upload object, but this would require a larger refactor of the storage services.

Comment on lines 43 to 49
AppProfiler.logger.info(
"[Profiler] data uploaded: " \
"profile_url=#{upload.url} " \
"profile_viewer_url=#{AppProfiler.profile_url_formatter.call(upload)}"
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the wording of the log here. Please review and I'll need to update the docs as well.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
AppProfiler.logger.info(
"[Profiler] data uploaded: " \
"profile_url=#{upload.url} " \
"profile_viewer_url=#{AppProfiler.profile_url_formatter.call(upload)}"
)
AppProfiler.logger.info(
<<~INFO.squish
[Profiler] data uploaded:
profile_url=#{upload.url}
profile_viewer_url=#{AppProfiler.profile_viewer_url(upload)}
INFO
)

Nit: We could use a heredoc for this multiline string instead

@@ -72,5 +75,9 @@ def profile_data_header
def profile_url_formatter=(block)
@@profile_url_formatter = block # rubocop:disable Style/ClassVars
end

def profile_url(upload)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def profile_url(upload)
def profile_viewer_url(upload)

If we're going to keep this method, we should name it to distinguish the difference between a profile url and a profile viewer url and use it in lib/app_profiler/profile.rb too. profile_url_formatter should also be renamed to profile_viewer_url_formatter, but we would need to do a deprecation cycle for that (so maybe we could consider doing this in another change).

Comment on lines 43 to 49
AppProfiler.logger.info(
"[Profiler] data uploaded: " \
"profile_url=#{upload.url} " \
"profile_viewer_url=#{AppProfiler.profile_url_formatter.call(upload)}"
)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
AppProfiler.logger.info(
"[Profiler] data uploaded: " \
"profile_url=#{upload.url} " \
"profile_viewer_url=#{AppProfiler.profile_url_formatter.call(upload)}"
)
AppProfiler.logger.info(
<<~INFO.squish
[Profiler] data uploaded:
profile_url=#{upload.url}
profile_viewer_url=#{AppProfiler.profile_viewer_url(upload)}
INFO
)

Nit: We could use a heredoc for this multiline string instead

@@ -35,7 +35,10 @@ module Viewer
mattr_accessor :autoredirect, default: false
mattr_reader :profile_header, default: "X-Profile"
mattr_accessor :context, default: nil
mattr_reader :profile_url_formatter, default: nil
mattr_reader :profile_url_formatter,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
mattr_reader :profile_url_formatter,
mattr_reader :profile_url_formatter, default: proc do |upload|
"#{AppProfiler.speedscope_host}#profileURL=#{upload.url}"
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gmcgibbon when I use do instead of braces I'm getting an error

`proc': tried to create Proc object without a block (ArgumentError)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, yeah sorry. Let's assign the proc to a constant and then assign the constant to the default.

@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

[Unreleased]: https://github.com/Shopify/app_profiler
- Log info with link to speedscope during file upload (#47)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- Log info with link to speedscope during file upload (#47)
- Log info with link to speedscope during file upload (#47)

Copy link
Member

@gmcgibbon gmcgibbon left a comment

Choose a reason for hiding this comment

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

LGTM after the proc fix. Please squash your commits before merging. Thanks!

PR review

pr review

make proc a const
@kimbilida kimbilida merged commit ca2b44c into main May 25, 2022
@kimbilida kimbilida deleted the kimb-log-speedscope-link branch May 25, 2022 18:46
@shopify-shipit shopify-shipit bot temporarily deployed to production June 16, 2022 13:21 Inactive
dalehamel added a commit that referenced this pull request Jun 24, 2022
This pull request was closed.
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.

3 participants