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

feat: add ingress events to timeline #2735

Merged
merged 1 commit into from
Sep 19, 2024
Merged

feat: add ingress events to timeline #2735

merged 1 commit into from
Sep 19, 2024

Conversation

wesbillman
Copy link
Member

Fixes #2518

Successful ingress request
Screenshot 2024-09-19 at 10 10 03 AM

Failed ingress request
Screenshot 2024-09-19 at 10 10 22 AM

@wesbillman wesbillman requested review from alecthomas and a team as code owners September 19, 2024 17:11
@wesbillman wesbillman requested review from deniseli and removed request for a team September 19, 2024 17:11
This was referenced Sep 19, 2024
@wesbillman wesbillman force-pushed the add-ingress-events branch 2 times, most recently from fd34982 to 11024ed Compare September 19, 2024 17:30
}
observability.Ingress.Request(r.Context(), r.Method, r.URL.Path, optional.Some(verbRef), startTime, optional.Some(errMsg))
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you mind changing the final optional.Some back to sending a static string instead of err.Error()? Otherwise the cardinality of the error field blows up and makes brad cry tears of money

Same for all the other observability calls

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do! I was under the impression that attributes changing would not increase billing, but it sounds like that's not the case so thanks for catching this! I was mostly trying to avoid all the duplication here, but sounds that duplication is useful in this case.

I'll try to clean this up with some helper functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahhh that makes sense. Thanks thanks!

Comment on lines 108 to 111
observability.Ingress.Request(r.Context(), r.Method, r.URL.Path, optional.Some(verbRef), startTime, optional.Some(err.Error()))
ingressEvent.Response = &http.Response{StatusCode: http.StatusInternalServerError}
ingressEvent.Error = optional.Some(err.Error())
timelineService.InsertHTTPIngress(r.Context(), &ingressEvent)
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about making a helper func for these, since there's the duplication between here and below?

Copy link
Member Author

Choose a reason for hiding this comment

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

So much duplication 😂 helpers to the rescue

Copy link
Member Author

Choose a reason for hiding this comment

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

The helper was gnarly to cover everything so I just made a helper for the new timeline error events. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

sweet sgtm!

func callEventToCall(event *CallEvent) *Call {
var response either.Either[*ftlv1.CallResponse, error]
if eventErr, ok := event.Error.Get(); ok {
err := errors.New(eventErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this err is only used on the line below, what do you think about inlining it as response = either.RightOf[*ftlv1.CallResponse](errors.New(eventErr))?

Request json.RawMessage `json:"request"`
RequestHeader json.RawMessage `json:"req_header"`
Response json.RawMessage `json:"response"`
ResponseHeader json.RawMessage `json:"res_header"`
Copy link
Contributor

Choose a reason for hiding this comment

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

ultra nitty nit: I don't think I've seen response abbreviated to res - only to resp. It is annoying that resp is 4 long while req is 3, so they don't match nicely then, but if I saw res_header with no context, I probably wouldn't guess what it is. What do you think? No strong feelings on my part

Error optional.Option[string] `json:"error,omitempty"`
}

type Ingress struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wanna nest this in IngressEvent?

Copy link
Member Author

Choose a reason for hiding this comment

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

I very much do, but they are a bit too different. Like when creating an event I never want the requestKey to be missing, but it's allowed to be in the db. Similar to Request and Response where since they are different types it might get confusing to users of the API.

I had to do something similar with CallEvent :(

Copy link
Contributor

Choose a reason for hiding this comment

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

ahhhh got it, that makes sense

Comment on lines 108 to 111
Request: []byte(`{}`),
RequestHeader: []byte("{}"),
Response: []byte(`{}`),
ResponseHeader: []byte("{}"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Two things:

  1. Should we add another test with more content in these fields to make sure all the json marshaling works correctly?
  2. I feel like I'm probably missing something but why do some of these have " and others have `?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. You bet!
  2. Nah, just copy/pasta errors :) Thanks for flagging!

Copy link
Member Author

Choose a reason for hiding this comment

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

This was surprisingly hard to decipher the json marshalling 😂

Copy link
Contributor

Choose a reason for hiding this comment

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

hehehe

Comment on lines +70 to +71
<ul className='pt-4 space-y-2'>
<li>
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we actually need all these to be wrapped in the <ul> and <li> elements?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's consistent with the other detail pages for now, but yeah we should probably take a pass at these at some point. I'm not sure we even want to leave this current layout tbh.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah that makes sense

Comment on lines +40 to +59
{selectedIngress.response !== 'null' && (
<>
<div className='text-sm pt-2'>Response</div>
<CodeBlock code={JSON.stringify(JSON.parse(selectedIngress.response), null, 2)} language='json' />
</>
)}

{selectedIngress.requestHeader !== 'null' && (
<>
<div className='text-sm pt-2'>Request Header</div>
<CodeBlock code={JSON.stringify(JSON.parse(selectedIngress.requestHeader), null, 2)} language='json' />
</>
)}

{selectedIngress.responseHeader !== 'null' && (
<>
<div className='text-sm pt-2'>Response Header</div>
<CodeBlock code={JSON.stringify(JSON.parse(selectedIngress.responseHeader), null, 2)} language='json' />
</>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

Since these are so similar, what do you think about adding a helper component that looks like:

const CodeBlockIfNotNull({ heading, maybeNullContent }) => {
  if (maybeNullContent === 'null') {
    return
  }
  return (
    <>
      <div className='text-sm pt-2'>{heading}</div>
      <CodeBlock code={JSON.stringify(JSON.parse(maybeNullContent), null, 2)} language='json' />
    </>
  )
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Same below for the attribute badges

Copy link
Member Author

Choose a reason for hiding this comment

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

I made a helper for the code blocks that are just strings but we'll want to rethink all of this with some better design so I don't want to spend too much effort on it just yet :)

Copy link
Contributor

Choose a reason for hiding this comment

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

sweet sgtm!

@wesbillman wesbillman merged commit bb94848 into main Sep 19, 2024
91 checks passed
@wesbillman wesbillman deleted the add-ingress-events branch September 19, 2024 23:19
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.

Add timeline records for ingress requests that failed before being called
2 participants