OBPIH-6733 add support for Sentry performance tracing#4898
OBPIH-6733 add support for Sentry performance tracing#4898
Conversation
|
Note that the changes here can be merged independently from the ones in my openboxes-devops PR https://github.com/openboxes/openboxes-devops/pull/74. All we're doing in this PR is enabling performance tracing. No DSN/environment changes are happening here. |
| logger: com.mysql.cj.jdbc.log.StandardLogger | ||
| type: org.apache.tomcat.jdbc.pool.DataSource | ||
|
|
||
| # Settings for database logging |
There was a problem hiding this comment.
I just reorganized these and added some comments for clarity. You can double-check, but nothing should be changed (except formatSql: false for development).
There was a problem hiding this comment.
At first it looked like you were adding new default properties, but then I realized you were just consolidating default properties that were in environment-specific blocks. So nothing to see here.
grails-app/conf/application.yml
Outdated
| url: jdbc:mysql://localhost:3306/openboxes?serverTimezone=UTC&useSSL=false | ||
| # P6Spy is an interceptor that allows us to log database queries. We use it in our Sentry integration. | ||
| driverClassName: com.p6spy.engine.spy.P6SpyDriver | ||
| url: jdbc:p6spy:mysql://localhost:3306/openboxes?serverTimezone=UTC&useSSL=false |
There was a problem hiding this comment.
let's discuss this. All this should be doing is adding an interceptor to capture the SQL queries, which then get forwarded on to the database as normal. Configuring it this way (via jdbc URL) is the recommended approach, though it does feel a bit weird.
Obviously we'll test it on a deployed environment but let me know if there's something that I'm missing about our setup that would prevent us from doing this.
|
@jmiranda @awalkowiak I was looking into database query logging while this was sitting in review and since I got it working I figured I'd just add it in now since I don't think either of you have had a chance to review this yet. It's ready for review, but if possible, lets try and test this PR on a deployed environment. |
| # The ratio of all requests to capture for performance tracing. 1.0 is 100% of requests. Disable tracing by setting | ||
| # a value of 0. We keep this number low (as recommended by Sentry) for performance reasons, but it can be increased | ||
| # if we decide we need more data. | ||
| traces-sample-rate=0.1 |
There was a problem hiding this comment.
this is the setting I was talking about in the tech huddle today with Andy. We only capture 10% of requests. We can adjust this as needed if we're seeing (or not seeing) a performance impact
There was a problem hiding this comment.
Can we adjust this via Ansible? I assume this file is only available post-deployment, so unless we have a way of making it overridable from openboxes.yml or by adding a sentry.properties override there. Anyway, there might be something that needs to change to make this work i.e. the config locations property defined in openboxes.yml.
There was a problem hiding this comment.
Good point. 10% is likely a safe bet, but it would definitely be useful to be able to configure this per environment and on the fly.
We could probably set it via environment variable with something like traces-sample-rate=${SENTRY_SAMPLE_RATE:0.1}
But I also want to take a look soon at why we're unable to set sentry properties in openboxes.yml. I totally agree that we should give people the option to configure their environments however they want.
There was a problem hiding this comment.
Yes, that would be awesome. Either setting it in openboxes.yml and/or as a environment variable that openboxes.yml will use to override it's default.
But this is not a concern for the PR.
|
@jmiranda @awalkowiak based on discussions in https://openboxes.slack.com/archives/C06JCHWR807/p1730398659510229 I disabled p6spy logging by default. It can be enabled on any environment by setting the following: which I'll document somewhere (along with any other monitoring info). I'd like to take some time in the future to try to figure out a more dynamic approach. Maybe a bean that gets created like this: which will auto-configure p6spy if sentry is enabled, but I'll save that for another time. I spent too long as is trying to get it to work. |
There's a Configure > Sentry page that needs some love. |
src/main/resources/sentry.properties
Outdated
|
|
||
| # If you ever need to debug Sentry changes locally, you can set the following properties. Note that any values | ||
| # defined here will be overridden by "SENTRY_DSN" and "SENTRY_ENVIRONMENT" environment variables if those are defined. | ||
| dsn=${SENTRY_DSN_BACKEND} |
There was a problem hiding this comment.
See https://github.com/openboxes/openboxes-devops/pull/74 for details on how this env var is being set.
| <pattern> | ||
| %date{ISO8601} %5level [%-10.10thread] %-40.40logger{40}: %message%n%xException | ||
| <!-- https://logback.qos.ch/manual/layouts.html --> | ||
| %cyan(%date{ISO8601}) %highlight(%-5level) %magenta([%thread]) %yellow(%logger{40}): %message%n%xException |
There was a problem hiding this comment.
I might have been wrong about the color issue. Here's the PR I was referring a few weeks ago re: "Matt removed something fancy that was causing issues on Bamboo". Turns out it was due to webpack, not our logging configuration.
grails-app/conf/logback.xml
Outdated
| <logger name="org.hibernate.transform" level="info" /> | ||
| <logger name="org.hibernate.tool" level="info" /> | ||
| <logger name="org.hibernate.type" level="info" /> | ||
| <logger name="org.hibernate.type" level="info" /><!-- https://www.javacodegeeks.com/2012/10/logging-hibernate-sql.html --> |
There was a problem hiding this comment.
Would you mind adding a comment to explain the blog post? Are you including to explain why it's used i.e. that it's to improve SQL logging?
There was a problem hiding this comment.
Yeah exactly. I'll add a comment to clarify
| // If we wanted our logs to look more like HTTP Requests, we could have done the following instead, but | ||
| // we decided that "invoiceApi/list" is easier to debug than "GET /openboxes/api/invoices". | ||
| //return "${var1.method} ${var1.requestURI}" | ||
| return "${var1.getAttribute("org.grails.CONTROLLER_NAME_ATTRIBUTE")}/${var1.getAttribute("org.grails.ACTION_NAME_ATTRIBUTE")}" |
There was a problem hiding this comment.
I understand that invoiceApi/list is easier to parse and figure out where to look, but using the URL Mapping seems to be a better choice.
Is there a way to make the choice configurable? I assume the easiest way would be to leave this class alone and handle the configuration in the SentryGrailsTracingFilter.
Note: I am not asking you to do it, just wondering what it would entail.
There was a problem hiding this comment.
I like this approach better (implementing a Sentry transaction name provider) but just wanted to point out that we're setting the transaction name for New Relic here.
Perhaps someday we'll want the transaction names to be consistent.
There was a problem hiding this comment.
Yeah we could make it configurable via an app setting. I already have the code for both options so I have no problem adding a property for this.
| */ | ||
| class GrailsHttpTransactionNameProvider implements TransactionNameProvider { | ||
|
|
||
| String provideTransactionName(HttpServletRequest var1) { |
There was a problem hiding this comment.
Could you change the var1 to request? Uness there's something I'm missing the var1 had me double-take a few times during the review of this code.
There was a problem hiding this comment.
I used var1 because that's what the abstract method in TransactionNameProvider uses and I remember you previously asked me to maintain method arg names from the interface. I agree that request is clearer though so I can change it
There was a problem hiding this comment.
Ugh. Yes, I did. :)
I assumed the arg1 was the default arg name provided by Intellij, but I guess that makes sense.
| } | ||
|
|
||
| SentryGrailsTracingFilter(final IHub hub) { | ||
| super(hub, new GrailsHttpTransactionNameProvider()) |
There was a problem hiding this comment.
I assume here we could use SpringMvcTransactionNameProvider to get the default behavior. Does the default behavior use the URL mapping?
There was a problem hiding this comment.
yes but it doesn't work with grails (nothing will ever get logged to sentry) so we'd need to provide our own implementation regardless. See that forum post linked in the class docstring if you're curious
|
|
||
| TransactionNameSource provideTransactionSource() { | ||
| // Do what SpringMvcTransactionNameProvider does, which is the provider that Sentry normally uses. | ||
| return TransactionNameSource.ROUTE |
There was a problem hiding this comment.
I don't know if this really matters, but is this accurate? I feel like custom would be more accurate since it doesn't seem like we're dealing with the parameters at all.
There was a problem hiding this comment.
Yeah good point. I originally had it using the URI approach, so ROUTE made more sense, but since we switched I think maybe COMPONENT makes the most sense since it's based off a Grails controller and method?
| # (mainly the P6LogFactory) so that we don't flood our system with P6Spy log files that we don't use. | ||
| # https://blog.sentry.io/troubleshooting-spring-boot-applications-with-sentry/#jdbc-instrumentation | ||
| modulelist=com.p6spy.engine.spy.P6SpyFactory | ||
| driverlist=com.mysql.jdbc.Driver |
There was a problem hiding this comment.
Do we still need this if p6spy is configured on the server?
There was a problem hiding this comment.
Enabling p6spy via:
dataSource:
driverClassName: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/openboxes?serverTimezone=UTC&useSSL=false
still requires the settings here for p6spy to be able to know what "real" driver to forward to after it does its thing.
from what I saw when implementing this, everyone was configuring this via spy.properties. I can't remember if it was a requirement for it to work or if it was smart enough to look in the application.yml file. I can test it out again.
There was a problem hiding this comment.
Yeah that's what i was thinking. Not a big deal. I just didn't want to keep a file around that wasn't necessary.
jmiranda
left a comment
There was a problem hiding this comment.
Review my comments in case I've uncovered anything that needs to be addressed. Otherise it looks good to me.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #4898 +/- ##
=========================================
Coverage ? 7.62%
Complexity ? 811
=========================================
Files ? 598
Lines ? 42190
Branches ? 10261
=========================================
Hits ? 3217
Misses ? 38504
Partials ? 469 ☔ View full report in Codecov by Sentry. |
✨ Description of Change
Link to GitHub issue or Jira ticket: https://pihemr.atlassian.net/browse/OBPIH-6733
Description: Start publishing performance traces to Sentry. Sentry doesn't have out-of-the-box support for Grails so I needed to implement it the SpringBoot way then to get it working with Grails I had to add the transaction name to each incoming API request in a custom filter.
Here's the test project I created when testing against my local: https://openboxes.sentry.io/performance/?project=4507488767115264
And a screenshot from it showing performance traces:
