 That's so welcome. I hope you guys are having a good Envoy Con in the beginning of KubeCon. So we're already starting a little bit late, so I'm going to try and rush through this, see if we can get to the meat of this a little quickly. So my name is Casey Kurosawa. I'm a support engineer or solutions engineer with Ambassador Labs. And we're going to be talking about Envoy Debug Locking. So I started my journey with Envoy a little more than a year ago, starting working with the now Amosary Project and working with clients and customers using our products and trying to figure out problems that they're having. And the default Envoy logs that come with the system are quite helpful. And very useful, but sometimes you want to dig a little bit deeper. But once you turn on that debug logging mode, you get flooded with a sudden massive wall of text. Once you take a look at it, it's a lot to take in. It's very overwhelming at first, and sometimes things aren't even necessarily in the order that you're expecting them, of course, because Envoy is a multi-threaded process and is able to handle simultaneous requests. So getting an understanding of the overall architecture of how the logs are structured can help us follow requests. So let's break it down and start one line at a time here. Looking at each individual aspect, we have the time stamp, which is pretty straightforward. We have the worker PID that's associated with a particular log line. We also have the log level, the component that is associated with it. And so this could be maybe a filter component, a routing component. You're most likely going to find these kinds of information here. You're also going to get the code source of where this particular action is taking place. And then the two pieces that I find the most useful are the connection ID and the stream ID. And now by utilizing both the time stamp and the stream ID, we're able to identify a particular set of information about a request as it's passing through the data plane, the Envoy data plane. And then finally, we can tie that request information to a particular action that takes place. So now let's actually follow an example connection as it passes through Envoy. So first we have the initial handshake. You can see as part of our logs here that we start out with an initial TLS handshake. It provides us the server name that was requested by the client. And we can see that after accepting that handshake, it initiates a new connection. Now after the connection has been established, and we can see the particular connection ID is C2988, it establishes a new stream and processes the headers. Now a couple of interesting things to note here. The first course is that we're utilizing our HTTP2 pseudo headers here. So any kind of identification of the host header is going to be part of that authority pseudo header as you're looking at it. The other thing is that you're going to also see a number of the various user agent and information that's being populated by the browser as well. And this can be another good way of identifying a particular request that you want to take a look at. And so at this point, we can now establish that that's the initial request that has come in, and it has been processed, and we get the header information that's associated with it. And now, because our proxy is utilizing the x.filter, we're going to take a short sidetrack here. And this is going to be the case for most filters, envoy filters that you have associated with your envoy instance. So in this particular case, we have an upstream xdoth at localhost port 8500. And it's doing a post request, and we can see that it is able to send the contents of the request and get an authorization response back. And you can also notice that it actually establishes a completely separate connection here but with a completely separate stream ID. And so this gives you proof in the actual logs that this is an actual synchronous process that is happening separately to what's happening with your request connection. And so now that we've established that this is authorized as part of our xdoth, we can now construct the proxied request that is intended for the upstream. And you can see that this will be the final contents of the request as it gets passed to the upstream cluster, including all kinds of header modifications. You'll notice that we get our xenvoy headers automatically attached as well. And so those can be inspected to see how those are interacting with the system, as well as some information if you were to look at the actual cluster in something like xds. You can see which specific upstream cluster is being matched for the particular URL and for what information. And now finally, envoy will actually construct a new connection, typically using the number following the initial request and is able to establish a new connection to this upstream and receives a response back that it then returns to the original client. And after the response is complete and it is established that it has finished sending this 200 response code, we see that it destroys the stream and completes the connection. And yeah, that's pretty much about it. So as kind of a general idea and the final takeaways here is that by understanding how to read the debug logs and in particular, how to associate these particular connection IDs and stream IDs, you can see the full process by which Envoy is able to handle data and handle network connections and get an understanding of the overall architecture and the overall process by which Envoy does its thing. So finally, just as a special thanks to Ambassador Labs, the company I work for, special thanks to EnvoyCon and KubeCon, as well as Daniel Bryant, who helped me in making this presentation. And as a side note, quick sort of plug, we are hiring and there are some links for more information about Ambassador Labs. Thank you.