getsentry / sentry-docs

Sentry's documentation (and tools to build it)
https://docs.sentry.io
Other
332 stars 1.45k forks source link

Improve ownership rule documentation for "module" and "path" #9641

Open damianw opened 7 months ago

damianw commented 7 months ago

Core or SDK?

Core Sentry product

Which part? Which one?

Ownership Rules

Description

The current Ownership Rules documentation gives the following options for types of matches:

Types of matches available:

  1. Path: matches against all file paths in the event's stack trace
  2. Module: matches against the module in the event's stack trace
  3. URL: matches against the event's url
  4. Tag: matches against event tags

Because an event in Sentry can have multiple exceptions, and each exception can have multiple stack frames, the first two are fairly ambiguous. What is the matching strategy when using path or module? A clearer explanation of this would help, as would some concrete examples.

For example, suppose I have the following Java stack trace:

kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 60000 ms
    at kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:191)
    at kotlinx.coroutines.TimeoutCoroutine.run(Timeout.kt:159)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by com.robinhood.coroutines.TimeoutException: kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 60000 ms
    at com.robinhood.coroutines.TimeoutKt.withTimeoutStacktrace(Timeout.kt:11)
    at com.robinhood.coroutines.TimeoutKt$withTimeoutStacktrace$1.invokeSuspend
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:32)
    at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:32)
    at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

If I use path, my understanding is that it would use the filename (as that it all that is available by default on JVM, which is understandable). If I use module, it's totally unclear what it's going to use - is it the package name of the exception classes, or perhaps the class names in the stacks? For both path and module, which exceptions and stack frames are matched? Is it only the first of each, or does it go through them all in order trying to find a match?

Suggested Solution

The documentation should be clearer about how these works, and provide some examples if possible.

It is possible to experimentally try to figure this out, but requires actually reporting events to Sentry to see what happens. It would be even better if Sentry provided a way to preview these rules, similar to the alerting rules.

getsantry[bot] commented 7 months ago

Assigning to @getsentry/support for routing ⏲️

getsantry[bot] commented 7 months ago

Routing to @getsentry/product-owners-docs for triage ⏲️

getsantry[bot] commented 7 months ago

Routing to @getsentry/product-owners-issues for triage ⏲️

MichaelSun48 commented 7 months ago

Hey @damianw! 👋 Thanks for the feedback! Let me first answer the questions you had:

If I use module ... Is it the package name of the exception classes, or perhaps the class names in the stacks?

We will match a module-type Ownership Rule to the classes in the stack trace, not the exception class

For both path and module, which exceptions and stack frames are matched? Is it only the first of each, or does it go through them all in order trying to find a match?

As per this section in our docs, we match a stack trace based on the highest matching rule in the Ownership Rules file. The order of the stack frames in the stack trace is not considered.

I agree that the Ownership Rules docs could be more clear on finer-details of how our logic works; I will route this over to our docs team internally to try and fill in those gaps.

Let me know if that doesn't make sense or if you have any other questions!

damianw commented 7 months ago

Thanks for the information, that's very helpful!

That section does answer some questions, but still leaves some gaps.

For one, it mentions this:

If there are multiple owners in the rule, left-to-right

It's not clear to me what "left-to-right" means in this context, since there doesn't seem to be anything to evaluate "left-to-right". I'm led to believe that having multiple owners in the rule means that all of them will be assigned, but this phrasing seems to imply that only the first will be assigned - if so, it would follow that every owner after the first in a rule is ignored, which doesn't seem to make sense.

That section explains further that:

After evaluation, the last rule matching returns the assignment. The order of the event’s stack trace filepaths is irrelevant in determining the rule assignment.

It would be helpful to include that the order of the module in the frames is also irrelevant (if that is indeed true). You also summarized this logic as "the highest matching rule", which seems to be the inverse of what's described here (that it's actually the last matching rule in the list)... that might be some evidence that it is actually unclear 😅

And as I mentioned, some better documentation about what module means would be helpful... perhaps linking to another page that explains what it represents in various languages.

Anyway, I think my questions are mostly answered, so thanks for taking the time and looking into this - really appreciate it!