-
Notifications
You must be signed in to change notification settings - Fork 261
Improve error handling throughout backend #50
Conversation
] | ||
}` | ||
|
||
assert.JSONEq(t, expect, resp.Body.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assert unfortunately fails randomly due to the fact that errors
in the JSON is an array (and therefore ordered). It is generated from validator.ValidationErrors
which is just a typedef for a map, and in Go maps are unordered (and actually intentionally randomized to prevent relying on any ordering).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do something shady like intentionally order the errors only when testing, or we could do some other shady stuff to do an unordered comparison, or we could change errors
to a map keyed on field
or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*The unordered comparison wouldn't be shady, would just be a hassle.
what do you think about moving this into it's own |
Yeah, it can totally go into it's own file. Eventually should go into it's own package I think, but we need to avoid a naming conflict with the built in |
"net/http" | ||
|
||
"github.com/Sirupsen/logrus" | ||
"github.com/gin-gonic/gin" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be awesome to see us use http.Request
and http.ResponseWriter
directly here to remove this library's dependency on gin. That's what I did with the sessions lib and wrote a wrapper function with get the req and resp from the context with c.Request
and c.Response
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make ReturnError
take an http.ResponseWriter
so it's called like ReturnError(c.Writer, err)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, that's cool. you'll have to set the content type and all that, but as the go proverb goes: "a little copying is better than a little dependency"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On further thought, what makes this different than any of the other places throughout the codebase that we use c.JSON()
? If we ever wanted to migrate off Gin we could change all of the call sites together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My hope is that we'll use the standard library http functionality whenever possible and one day, we'll look at the codebase and say "oh, we actually don't use gin for much" and cut it. But if we continue to use all of it's features, even if we don't realllllly need to, then it will feel like a more daunting task to move away from it in the future IMO.
@marpaia Can you confirm you are good with this API before I start converting the codebase to use it? |
} | ||
|
||
func (e *KolideError) Error() string { | ||
return e.PublicMessage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the logic with this being PublicMessage
vs PrivateMessage
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PublicMessage
is safe to be returned to the client. PrivateMessage
is the detailed error information. Right now we log PrivateMessage
at a debug level but we could also send it to a log aggregator or any other analysis.
I should add some docstrings on all this.
@zwass shouldn't there be a |
Yeah, a basic |
Perhaps in addition to |
There are actually only a few places that Another note, we could return the
|
Fine with me, if the call sites are minimal and you're going to update them all. Yeah, that's awesome! I added debug state to the config, so it's |
Cool, it sounds like there is basic agreement on this, so I'll go about doing the refactoring and incorporate your comments. |
@marpaia Please take a look at this when you get a chance. I think I am mostly done with my intended changes so now I need your comments to finish it up. |
func DatabaseError(c *gin.Context) { | ||
c.JSON(500, ServerError("Database error")) | ||
} | ||
|
||
// UnauthorizedError emits a response that is appropriate in the event that a | ||
// request is received by a user which is not authorized to carry out the | ||
// requested action | ||
func UnauthorizedError(c *gin.Context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we make all of these require an extra string so we can throw in a longer error which can be used as the private message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah I wanted to mention that it would be great if we could refactor the authorization code to use KolideError
to put more helpful information in at the site of the error and then eliminate this function. I felt like the scope of this PR kept creeeeping so I just shimmed this for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if so, then this LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also gotta say it's awesome that you immediately zeroed in on my least favorite part of this PR :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hah, it's what i hate the most about error management at the moment, probably 30% of the errors returned aren't even the correct error. needs love for sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted in #57.
WIP of the new standardized format for error reporting.
The proposal is that errors throughout the codebase are reported as
KolideError
where possible (with the exception of validation errors which usevalidator.ValidationErrors
). There is a rudimentary implementation ofReturnError
which will process the error and output public error information.Private information is also debug logged. Having this central function allows
us to plug in any other error reporting mechanism we would like in the future.