skip to content

Debugging complicated apps

When you’ve got a frontend, a backend, and more in between, how do you debug issues? Lazar Nikolov teaches us how to use tracing.

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON LENGSTORF: Hello, everyone, and welcome to another episode of Learn With Jason. Today, on the show, we're going to be tackling something that I think most of us try not to think about because it's hard. And, you know, as much as we prefer not to deal with hard things sometimes, we just don't have a choice because that's what jobs are most of the time. I'm bringing in support today and we're going to be learning how to do hard things with a little help from my friend, Lazar.

LAZAR NIKOLOV: Hey, friends.

JASON LENGSTORF: I'm very excited to have you here and dig into this topic. For folks not familiar with you and your work, can you give us a background on yourself?

LAZAR NIKOLOV: Yeah, sure, I'm a developer advocate at Sentry. Yeah, I like to fix hard problems. [Laughter]. That's a good intro. I like to fix hard problems. Yeah.

JASON LENGSTORF: Yeah, I mean, it truly is, like, a deep part of this profession, I think, is getting into some just very tangled knots. Almost Gordian knots if you're into that sort of thing. [Laughter]. So what I� what I want to talk about is how we get into debugging really complex apps. A lot of my experience coming up, we talked about debugging, but we talked about it from the standpoint of fairly concise functions. Find the bug in this function and that starts out hard, like, when we're new to coding, that is already a very challenging thing to do but then we start to build bigger and bigger things and we go from having one function to having a dozen or more or having a function in a repo to having multiple repos and those are all projects that depend on each other. Maybe we get into microservices or crossteam stuff and suddenly when we're debugging, it's not just debugging the code in front of us, it's debugging everything that goes on throughout this app. There's a frontend that's talking to a backend that's talking to a service or a thirdparty. If we change something, it could have effects.
It's our job to learn how to understand these very complex systems and not break things inadvertently when I fix one problem over here. I don't want to create a new problem over there. So, how? How do we do it?
[Laughter]. Fix us, please, in 50 words or less. [Laughter].

LAZAR NIKOLOV: I'm going to break that rule. But there are tools. Right. So, when we start learning programming, the concepts of writing code, there's, like, a huge learning curve but then we get into debugging, we have log messages, console.log, that's pretty hard, as well. We got debugger debugging, that's still a learning curve, as well. We haven't even gotten out of our development environments. This is all on your personal machine, debugging and localhost, it's hard but it's still nothing compared to debugging issues in production. You is databases, caches, your frontend is JavaScript, your backend might be in Python. That's why we have Sentry. Aside from looking at console logging and messages, how we can use those to debug, et cetera. Et cetera.

JASON LENGSTORF: Chat, I want to hear from y'all. I'm still, more or less, a consolelog debugger. I don't use it in practice. You tell me, what's your usual debugging practice? Are you a consolelog? Do you use debuggers?
Let's talk a little bit about how, like, how does any of this stuff to start to make sense when you start adding tools? You know, as a selfconfessed consolelog debugger, I have to basically drop a marble into the machine and then follow that marble to wherever it ends up and, you know, I'm logging, stepbystep, to figure out where did the marble fall off the track so I can go in and fix that.
How do I make that easier with a tool, I guess, is maybe the highlevel question or what does the tool do that makes that easier on my behalf?

LAZAR NIKOLOV: Yeah. So, I think what you're referring to is called tracing. When we are, for example, implementing tracing, we are creating, like, a snapshot of that marble.

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: And where it went and all of the data that can be gathered from all of the points, right, all of the little regions and turning points of where the marble went. When you isolate that path for a specific request, right, there's a marble per request or there's� there can be a separate marble that's within the same request, but we want to track something else, like a parallel process. When we see that and when we follow the marble across multiple� we don't have a word for this now. We're using "marble," but now we have services.
When we follow the marble across multiple services, we get a clearer picture as to what's happening and, yeah, how� where key can go from that point.

JASON LENGSTORF: And, so this is interesting because what it� like, one of the things that I have noticed is when I start doing consolelog debugging, it is a little embarrass to do that in production. I'm not saying I don't do that. You have to ship a console log and you know you're going to ship another commitlater. But also, the other thing that you're talking about here is this sort of, you get the data over time in a trace, whereas with the console log, it's at that exact moment so if you didn't think to log at the exact point where things broke, you'll actually not catch it. You'll see the snapshot ahead or snapshot behind and not where it went wrong.
That, in and of itself, sounds like something that would save me some time, especially if you're trying to debug off of your machine. That kind of console logging can be so slow. Maybe it's a minute or five minutes, maybe it's more. My focus doesn't make it through multiple ones. Being able to do this quickly, through a trace, feels like that, in and of itself, is a pretty huge win.

LAZAR NIKOLOV: Buckle up for this demo then. [Laughter].

JASON LENGSTORF: I'm ready. I'm so ready. I know you had a million things that you were going to try to show me today so let me stop jabbering and instead, get us over into this view here, where we are going to talk about� first and foremost, our captioning. So, this show, like every show, is being livecaptioned. We've got Vanessa here, from White Coat Captioning, the link is scrolling across the bottom of the screen here. You can follow that along. Human captioning is amazing. Thank you, White Coat Captioning. That is made possible through the support of our sponsor, Tuple.
Today, Lazar and I are using Tuple. He is going to be able to draw on the screen and send over links. If I get really stuck, he can take over the keyboard and actually type on my behalf. It's a very nice tool if you're pair programming. It's huge. And thank you, Tuple, for kicking in to make the show possible.
We're talking to Lazar, so let me drop a link, here, to...Lazar's Bluesky, because that's where we're hanging out these days, everybody. We're going to be talking about Sentry, which I think redirected me to my dashboard. Let me send the root URL here. There we go. So, we'll drop one of those in.
All right. So, that's the extent of the information that I have so I'm going to ask you, what  what do I do next? What's our first step here?

LAZAR NIKOLOV: Let's prepare our code. I prepared a demo for today's episode, so let's go to GitHub/� should I just paste the URL?

JASON LENGSTORF: We got the tools. You can just shoot it right in here.

LAZAR NIKOLOV: Let me see. Let me see. Let me see. This is text. This is just showing text.

JASON LENGSTORF: No, there's a little link thing at the top of the screen share. If you click that link thing, you should be able to paste a link.

LAZAR NIKOLOV: Link thing. There we go. I got it right. Yes, I did.

JASON LENGSTORF: There we are. Let me drop this into the chat for everybody.

LAZAR NIKOLOV: This is a template repo.

JASON LENGSTORF: So, I'm going to create a new repository. And that's the template. We'll put it on the Learn With Jason and then we'll call this "debugging flashcards." Okay. We'll make it public and off we go.

LAZAR NIKOLOV: Nice. So, we're going to clone this one.

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: And we're also going to make sure we have a Sentry account.

JASON LENGSTORF: I do. So I'm going to sign in.

LAZAR NIKOLOV: Uhhuh. Sign in and we are going to�

JASON LENGSTORF: And�

LAZAR NIKOLOV: That's going to be later.

JASON LENGSTORF: Let me get a� let me get this going here...how do I� what do I want to do? I'm going to open up a new� nope. New one of these. Close this one down. We're going to go over here, into GitHub and Learn With Jason and then we're going to GitHub repo clone and this one. Okay. So, then we're going to open that one up.

LAZAR NIKOLOV: Nice. All right. So, uh, demo first. We have a, like, a� it's not a mono repo, just a repo with two different projects, the API is the backend, which is in Django and the next is in Go. We have a YAML file. We have the API there and we also have the web there. So, the web� this is the development environment. If we want to use it, we can but we're going to use the production. We are running in production, that means things are minified. We can't really look at, you know, stack traces, it's all just mushed up, scrambled together. Yeah, that's the thing.
We need to have Docker running and we'll do Docker Compose Up.

JASON LENGSTORF: Do I need to do an NPMinstall? Docker, Compose, Up.

LAZAR NIKOLOV: This is going to boot up everything.

JASON LENGSTORF: I checked that Docker worked on my machine, before we got on this call, because I've been bit by that before.

LAZAR NIKOLOV: This is going to do Npminstall inside of those containers.

JASON LENGSTORF: Oh, I understand.

LAZAR NIKOLOV: We're going to do that later. For now, we'll just boot everything up, you know, click around, see how the application looks like. And, yeah. I can� we can point out the three bugs that we are going to be looking at today. And those three bugs are going to be, like, more and more complex.

JASON LENGSTORF: So I want to pull this up while we're waiting for Docker to run. There's major keyboard envy today. We did not coordinate this, but we absolutely match. Look at this. We got split keyboards, notebook in the middle, look at us. Huh. Basically twins. [Laughter]. Let's see, so, we're almost here. Looks like we're getting close. There we go. Everything's running on the side.

LAZAR NIKOLOV: You have a container name, DB is already in use.

JASON LENGSTORF: What, what? Have to rename or remove�

LAZAR NIKOLOV: Docker, Stop and...

JASON LENGSTORF: Great. What� let's see, what am I doing here?

LAZAR NIKOLOV: Maybe I should have named that. Let's try this. This is off the script. Go to the Compose YAML and go to the DB, change that� do, I don't know, flashcardsDB.

JASON LENGSTORF: And that won't break everything else?

LAZAR NIKOLOV: It should be a separate container now.

JASON LENGSTORF: Let's run that again. Now it's doing the flashcards DB thing.

LAZAR NIKOLOV: Precached. Migrations. We can do on localhost 3000 and start playing around with the demo.

JASON LENGSTORF: All right. So, here's localhost 3000.

LAZAR NIKOLOV: Nice, there we go. This is the flashcards application. This was initially built as a� you're in an alternate universe and the� you're basically employed to a lot of super stores and all of the super stores, they have different products, you got to know where they are, in which department. For example, if you want� I don't know� chicken drums, go to the butcher, poultry. So things might get a bit weird. So categories are going to be the super stores and flashcards are going to be the products, right.
We can actually dive right into the first issue. Let's create flashcards� sorry, category. Category and name it, I don't know, "Walmart," for example. There we go. So, we have a category, we don't have any flashcards. What will happen if we go to Practice and try to practice that? So, it says "see the browser console for more information." Go to the browser console. Do you like this information?

JASON LENGSTORF: This looks like how I debug. [Laughter].

LAZAR NIKOLOV: Right. But we don't know where that is. Right. If you search the question, there's going to be a lot of mentions and if you try to click into one of these files, again�

JASON LENGSTORF: Yeah, not great.

LAZAR NIKOLOV: Minified. It's in production. We're going to install Sentry and convert this type of error into something a lot more tangible. Actually� it's going to be a production error, but as if it was in dev time. Stop the Docker now. We're going to install Sentry in both projects.

JASON LENGSTORF: Okay. Do I do that by going in to each one separately?

LAZAR NIKOLOV: We need to create some projects first. Go to Packages Web and stay there. We are going to go into Web and I'll go into Sentry and we're going to create two projects.

JASON LENGSTORF: Projects.

LAZAR NIKOLOV: Projects, yeah. Topright. There we go. And let's create the Next.js first. So we already have a Next.js.

JASON LENGSTORF: Am I looking right at it? I knew that this was going to be helpful. [Laughter].

LAZAR NIKOLOV: So, we're creating a project. So, first and foremost, Sentry gets installed into your project. We have framework, language and even frameworkspecific, because we tap into the framework and use the lifecycle hooks, use all the data that framework gives us in that way� that's how we provide the most debugging context, whenever issues happen, whenever, like, performance issues happen, et cetera, this is why we need to install. It's not like a, here's the JavaScript generic browser SDK, it doesn't matter if you're in Vue.js or Next.js, we tap into the framework. Even better, more data, right. Then we set up the alert frequency, if we want to have emails or if we want to notify us with, like, Slack or, you know, Discord, or, you know, Microsoft Teams. If you're using that, my condolences. [Laughter]. If you want to get notified, we'll find you where you are and we'll send you a message that, you know, something's on fire.

JASON LENGSTORF: That's a good tag line for Sentry, we'll fine you. [Laughter]. All right. So I'm going to create this.

LAZAR NIKOLOV: And this is going to be the Next.js one. And look at that. Just copypaste.

JASON LENGSTORF: We're pulling a Wizard. Good, good, good.

LAZAR NIKOLOV: You have the org, you have the projects.

JASON LENGSTORF: I'm already in Web so I run it in this Web project.

LAZAR NIKOLOV: The wizard is going to do a lot of things. Yeah, install it. First, the wizard knows we're talking about a Next.js application because we gave that flag, "i."

JASON LENGSTORF: It's not going to touch the Compose, so we should be fine. Do I have a Sentry account, I do.

LAZAR NIKOLOV: It's authenticated, it's installing Sentry Next.js. What this is going to do, it's going to create a whole bunch of things for the client, for the server, et cetera. Let's talk about this now. Do you want to route Sentry request in the browser through your Next.js to avoid ad blockers. Ad blockers are vicious. If your website is hosted on mywebsite.com, and the ad blocker sees a request, it's going to think it might be an ad or analytics tool so it's going to block it. If 100% of your users use ad blockers, you're not going to use any data. It's almost never the case that 100% of the users use ad blockers. What we built into the Next.js SDK is a little tunnel. So instead of the browser sending the request to the Sentry.i0 directly, it is going to send it to processor so we will fool the ad blocker into saying, yeah, this is� this is my own implementation, it's my own monitoring. It's not analytics, it's not thirdparty. I'm just going to route it here. It's not going to get blocked. If you host this on Vercel, that means more traffic, more serverless functions, that means more money. Have that in mind. It's always� it depends. In this case, we don't want to do that. But if you wonder what that is, that's what that is. Proxy.

JASON LENGSTORF: Got it. Got it. Do we want to enable React component annotations?

LAZAR NIKOLOV: I can show you what this does later, in a few minutes. Tracing.

JASON LENGSTORF: Session replay? This is a cool feature. So, session replay, if I understand correctly� really, just whenever. You can configure it to be when someone has an error, we can see what they were doing in the app when the error occurred so it's almost like having a screen recording?

LAZAR NIKOLOV: It's like a DOM recording, it's pretty cool.

JASON LENGSTORF: This anonymizes. This is what somebody was doing on the screen, but the� the user info is gone and it's still, like� we're not spying on people. We're just trying to understand why our app is broken.

LAZAR NIKOLOV: We are very into privacy and hiding PII. It gets scrubbed in multiple places. The way that we handle, like, anything that's text or image get, like, [Indiscernible] the text gets replaced with stars and it's� Sentry implements an optout model instead of an optin.

JASON LENGSTORF: Which is really important. If you don't have an optout model, you're going to send every bit of data to�

LAZAR NIKOLOV: The other way.

JASON LENGSTORF: Right.

LAZAR NIKOLOV: You're not sending any data unless you manually annotate it.

JASON LENGSTORF: That's really, really good. That means that most of the time, we don't need to know what's on the screen. We need to know what page they were on and what broke and so then, you know, we can kind of safety� we don't need any of the text. We know what the pages on the site look like. But if it is critical, you can just optin the headline so you can see what section of the wizard they were in when it broke.

LAZAR NIKOLOV: Yeah, ALT elements. Yeah.

JASON LENGSTORF: So it's asking me if I want to create an example page. And I'm assuming because we already have a site set up, we don't need this.

LAZAR NIKOLOV: If you have me as a guest, we probably don't need to.

JASON LENGSTORF: Do we want to keep the CI/CD?

LAZAR NIKOLOV: This is only going to show you the API key on the screen. You can set that as an environment variable. So, no. You are going to have a file. Docker image is going to be in there. That's for source maps and we'll� we'll talk about that later.
So, we got this. Let's go to the API now. And do the same.

JASON LENGSTORF: Okay. So, we go to the API. We're going to call this one "debugging flashcards API." You say it was Django.

LAZAR NIKOLOV: We're not going to do this. Go to the requirements.txt file and copy the text within. I'm going to show you.

JASON LENGSTORF: Requirements.txt.

LAZAR NIKOLOV: This is package.json in a way.

JASON LENGSTORF: Wait, where do we put this?

LAZAR NIKOLOV: You just need to add Sentry SDK at the bottom. Sentry/SDK and then in Square Boys, you're going to write "Django." Just�

JASON LENGSTORF: Like that?

LAZAR NIKOLOV: You can fix it to a certain version but for this purpose, we'll just keep it like this.
Then we're going to go into the settings.py and basically do this. This is a [Indiscernible] type of project. Go to share it, presentation. Goddamnit, not presentation, Django. Settings.

JASON LENGSTORF: Got it. So I'm grabbing this bit here and I just drop this right� anywhere or?

LAZAR NIKOLOV: Above the read_env. Load up the environment first, just in case, and then initialize the SDK.

JASON LENGSTORF: Got it. Okay. We'll move this up to� oh, my goodness. Please stop. Help less. There we go. There we go. Like that.

LAZAR NIKOLOV: So we're initializing your organization, your project and your Sentry instance. We are fair source. That means you can grab Sentry's code and put it on your server. Right. And, the DSN is going to go to your domain, wherever you put it. But if you don't want do that, you can use the Sentry SaaS, the platform, itself. And it's free to get started. There's a free developer account. And, then it� the pricing is interesting because it's like a DIY. You can buy more if you need them and not buy other stuff or buy more performance. So it's like a DIY payment plan.
We're missing one thing here. Aside from the DSN, we have the trace. 100% of the transactions are going to be sent. For development, this is fine. But never push 1.0 in production. Set it to, like, 15% and then, like, slowly� gradually go up.

JASON LENGSTORF: Got it.

LAZAR NIKOLOV: And then we're going to add Profile Sample Rate.

JASON LENGSTORF: Do we want to keep it at 100 for dev?

LAZAR NIKOLOV: Right. Now let's go back to the Sentry� we're going to go back to the Web.

JASON LENGSTORF: Web Project.

LAZAR NIKOLOV: In the code. In the code.

JASON LENGSTORF: In the code. In the code.

LAZAR NIKOLOV: Open the Sentry Config for the server. It's a file at the root of the Web.

JASON LENGSTORF: Sentry Server Config.

LAZAR NIKOLOV: You can add Trace Propagation Targets. We're going to add localhosts and another string, API, with lowercase. This is because localhost is by default and API is how the API is named within the Docker Compose network. What this is means is whenever we're creating transactions� we're starting traces and we're sending it off to this different origin, we want to propagate that so we can continue, you know, the trace on the backend. This is the� that's the connection there.

JASON LENGSTORF: Excellent. Okay. Cool. All right. So then, do I need to rebuild this or?

LAZAR NIKOLOV: Yeah. Let's go back to the root and we can do, like, Docker Compose Up and, "//build."

JASON LENGSTORF: I have been hydrating superhard, way too hard and so I need to use the restroom so while this builds, I'm going to run away and if gets done before I get back, feel free to take over the screen and I'll catch up. I'm so sorry, I'll be right back.

LAZAR NIKOLOV: No worries. That's why I didn't get any water. I was afraid this was going to happen.
Oh, look at that. What do we have now? It says "log file not found." Oh, I know. So this...we did Docker Ps, we're going to see. Let's do "Docker Compose Down" and actually type that correctly. This is going to� there we go. Remove the existing containers. And now, let's do Docker Compose Up and then "//build," because we want to rebuild the API and the Web. Nope, I guess I'm going to need to� I guess I'm going to need to prune a bunch of stuff. Delete the image.
Yeah, I never got this right.
Jason, do you have a lot of Docker images locally?

JASON LENGSTORF: I don't think so. [Laughter].

LAZAR NIKOLOV: Can I do this?

JASON LENGSTORF: Sure.

LAZAR NIKOLOV: It's going to save up a lot of space. It's basically deleting images, et cetera.

JASON LENGSTORF: Oh, yeah, 2 gigs of space I was not using.

LAZAR NIKOLOV: Yeah. And now we're going to claim that back.

JASON LENGSTORF: That's helpful.

LAZAR NIKOLOV: Let's see. We didn't pray to the demo gods. A little hiccup there, but we can recover this. [Laughter].

JASON LENGSTORF: We're going to do great here. I also� yeah, I know. Like, the thing about water is that everybody's like, oh, yeah, you should hydrate, keep hydrating. Definitely hydrate and then they don't tell you there's zero chance you're going to be able to sit still for 90 minutes. [Laughter]. Let's see, how we� how we doing here?

LAZAR NIKOLOV: What is this? Uh, let's see. It keeps complaining about the log file.

JASON LENGSTORF: Oh, come on. Don't do this to me. Okay. I know what this is. I've had this issue on my computer. I don't fullyunderstand that it is. But the way that we solve it is instead of using CI, we just have it NPMinstall so let me get to the web here.

LAZAR NIKOLOV: There's a "Dockerfileprod."

JASON LENGSTORF: Dockerfileprod.

LAZAR NIKOLOV: You're going to find it there. This is where I'm creating the image. It's using Node 18.

JASON LENGSTORF: I had this issue when I was trying to do some stuff on Fly and it kept failing and, like, nobody can reproduce this issue so I have a magicallyscrewed up computer that, for some reason, like, NPM CI, does not work anymore. This should� should fix it.

LAZAR NIKOLOV: Yeah. Good to know.

JASON LENGSTORF: Probably. We'll see...

LAZAR NIKOLOV: Got this Docker file from the Next.js example repo.

JASON LENGSTORF: Uhhuh.

LAZAR NIKOLOV: So it's, like, a twostage build process. We're building first and then we're only creating the image out of the deliverables. There we go.

JASON LENGSTORF: Here we go. Somebody's asking, is Sentry something like Datadog? I think the chronological answer is Datadog's something like Sentry, right?
[Laughter].

LAZAR NIKOLOV: Pretty much. There are differences and there are similarities, as well. I know people want to use Sentry because it's cheaper. Something to have in mind.

JASON LENGSTORF: Let's see, so...things are actually working now. I'm very exciting about this. Someone is asking about your keyboard. You got the Voyager.

LAZAR NIKOLOV: I have the Voyager. Someone is asking about mounts?

JASON LENGSTORF: You have rigged yourself up a stand?

LAZAR NIKOLOV: Yeah. This is for smartphones.

JASON LENGSTORF: Meanwhile, I spent extra to get the custom, machined, 9pound stand for this Moonlander Keyboard, which I will say, I do like it because it doesn't slide. I bet that thing you rigged up has a rubber mat on it so it won't move and it would have probably solved the same problem with a lot less money.

LAZAR NIKOLOV: We're back up. We installed Sentry into the API and web projects. We connected those two so whenever we start an operation, it's going to ping the Next.js backend and ping the� so, let's do this again. Go� go inspect element now, real quick, just so I can show you what React did. Go to the console. This is still mushed up. Click on the first one and you get something interesting. You see that "data Sentry source file."

JASON LENGSTORF: Ooohhh, look at this!

LAZAR NIKOLOV: This is the bundle size. We'll increment thingy. We parse this later on the backend in Sentry and we're going to show you a really� as if you were in development. It's actually debugging in production. Right.
So, let's go to Sentry now because we� we have a� a little letter waiting for us there. Go to Issues.

JASON LENGSTORF: Issues. I'm in the� let's see, this is the API. I'm looking at the web, right?

LAZAR NIKOLOV: There we go. This is the undefined, right. Click into it and look at that. You see the� the code snippet at the bottom, the stack trace.

JASON LENGSTORF: Oh, this is from the source code.

LAZAR NIKOLOV: In production. It's still mushed up but because when we used the wizard, it actually implemented a Webpack hook, when you run npmbuild, it will upload it to Sentry for you so when an error happens, we get the stack trace and hit it against the source map. We don't ship the source code to the browser, that's it.
So, this is how we can actually debug things now.

JASON LENGSTORF: Yeahhhhh, okay. All right.

LAZAR NIKOLOV: These are the annotations that we saw and this is basically the issue details screen. We have a lot of stuff, so let's go up. This� for example, as opposed to other, you know, tools out there, we are grouping the issues. So, if 100 users experience this on the question, there's not going to be 100 issues. There's going to be one issue, it's going to tell you that 100 times happened and 100 users were affected.

JASON LENGSTORF: Ahhhh, nice. Very nice.

LAZAR NIKOLOV: You can set your priority here, right. If you want to set it to high, to low, this is basically all you here. You get some event highlights, like, what is the production. What is the level? What's the release if you have custom release tags, 1.0, 1.1, especially useful for mobile developers. In this case, it's the page/practice. We can also track users but it's not tracking out of the box. Right. We can assign this issue to one of our team members. I'm not sure if you have�

JASON LENGSTORF: I got me.

LAZAR NIKOLOV: You can assign it to someone. In the last 24 hours or 30 days, how much it happened. Is it regressing? Is it an old issue or is it a new issue? Release is at the bottom. We can scroll down and talk about the solutions hub.

JASON LENGSTORF: Issues, releases tracking. If I wanted to hire this off into GitHub?

LAZAR NIKOLOV: Yeah. We can set up the GitHub integration and this will open a GitHub issue for or Jira or any of the project management platforms out there and we also have the tags and what I love about the tags is that we can help� we can use tags to help us identify the priority. Because these are automatically set for us, but that doesn't mean that we can't set them ourselves so when a user logs in, I'm still going to keep their identity, but I'm going to check on their type. If it's an enterprise user, I'm going to say, "enterprise." This gives us, like, an aggregation. 100% of the errors belong to this user. If this was, like, a type of user, it's going to be, like, a division, right. If this issue affect more enterprise users, you're going to put that as a P0. If it's a free user, P3, maybe. That's how you can use tags to make decisions.

JASON LENGSTORF: Got it.

LAZAR NIKOLOV: Yeah. Then we have session replay. I'm going to fly through this. It's a DOM recording. Everything is stars.

JASON LENGSTORF: The information, itself, isn't being displayed. So we're not leaking any, like, data about who I am, anything like that. We just get to see� but, like, we can recognize where we are in the app from this.

LAZAR NIKOLOV: This is the short� the short view of session replay. We're going to, like, dive into session replay a bit later. And then at the bottom, we have bread crumbs and a whole bunch of other information but right now, I want you to go all the way up to and we're going to check out the Solutions Hub, topright.
We literally launched this two days ago. If this is slow, that means a lot of people are testing it out right now. What we're doing is, we're using AI to solve our issue. So we're not just, like, coding with AI, we're debugging with AI now. This is the first AI debugger in the world.

JASON LENGSTORF: Oh, look at this. Explicit permission to train a model on my data. Who knew?
[Laughter].

LAZAR NIKOLOV: It's going to try to figure out what's wrong. It has the source maps. It has the source code. It has the GitHub integration. Right. All these things. Flashcards might not be formatted correctly.
Scroll to the bottom now. Hit "close." And open it again. There should be something at the bottom.

JASON LENGSTORF: Let me refresh in case...open Autofix.

LAZAR NIKOLOV: We can give them more context, but it's optional. You can just, like, hit the button.

JASON LENGSTORF: Okay...

LAZAR NIKOLOV: There we go. Now it's crunching.

JASON LENGSTORF: A rubber ducky.

LAZAR NIKOLOV: So it's analyzing the issue. It's looking at the source. Arises from the undefined "display flashcard." Indicates that flashcards may be empty due to an incomplete API. It's going to give us these messages.

JASON LENGSTORF: We can see it thinking down here.

LAZAR NIKOLOV: Yeah. Before the API is fullyprocessed, leading to undefined. It's looking into two different scenarios, as we can see. It's not properly initialized or empty and we're trying to access it or it might be a raised condition error. It might be trying to access the flashcards before they even load. It's going to be the first one.
All right. So, there we go. Missing suspense boundary leading to premature render attempt. You can look at it. And, um, this error is a raised condition where the component attempts before the data has been fetched and processed. So, if we� if you worked on this project, you're going to know what this is because you know it's a file now. I mean, here's the "display flashcard." You can see the file on the left, here. We can use the suggested root cause or provide our own if we think we're smarter, so let's do that.

JASON LENGSTORF: We're going to propose our own.

LAZAR NIKOLOV: Root cause is just going to use this. We're going to say, display flashcards array is empty. The API returns an empty response, or something like that. Yeah. All right. Find the fix.

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: It's going to crunch a bit more. It's going to figure out how to fix this and it's going to give us a suggestion. We're going to look at it. If the suggestion looks good to us, we are going to� you know, we're going to give it a thumbsup�

JASON LENGSTORF: There we go, that's what we needed. Check for empty. Good.

LAZAR NIKOLOV: There we go. To prevent runtime errors. That's exactly the fix, right. Like, an empty state. We don't have an empty state.

JASON LENGSTORF: Yeah. All right. Good job, robot.

LAZAR NIKOLOV: Yeah. Now it's going to ask us, do we want a PR out of this and we're going to say, yeah. It's literally going to create a PR in our repo so we can go and merge it but right now, it's writing code for us.

JASON LENGSTORF: Got it. Got it.

LAZAR NIKOLOV: And, all right.

JASON LENGSTORF: No flashcards available for this category. That seems right.

LAZAR NIKOLOV: It's thinking in the right direction.

JASON LENGSTORF: I really want� I want this, like, AI code assistant to have, like, a little avatar and then whenever I'm happy, instead of, like, giving it a thumbsup, I want to give it a head pat. Like, good job, little buddy.
Implement loading and error states in the UI. Good, good, I like that. Checks it's an array, otherwise it gives it an empty. I'm happy with that. It replaces them, as is. That's what we want.

LAZAR NIKOLOV: So, let's go to "approve changes." You have the opportunity to go back and forth with this bot. Right now, we'll say, yeah, this is what we want so let's create a PR.

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: And now install the Autofix to the org and repo�

JASON LENGSTORF: I need to get out of some of these orgs. I'm in so many. Select repository.

LAZAR NIKOLOV: That one.

JASON LENGSTORF: That's...

LAZAR NIKOLOV: Has already been installed. That's the GitHub one. Try that again. If not, we can try the old repositories and we can delete that later, if you don't want to.

JASON LENGSTORF: What's going on? Debug. It's already there. Yeah, it's already installed because it's not even finding the one that's not there.

LAZAR NIKOLOV: Okay. Can you go back to Sentry and it should give us...

JASON LENGSTORF: GitHub app has already been installed. Okay. I'm going to close this one. I think I might have kicked it twice and it ran twice.

LAZAR NIKOLOV: Back to Autofix again.

JASON LENGSTORF: Approve changes. Create PR. And now... and now�

LAZAR NIKOLOV: Drum roll.

JASON LENGSTORF: PR. And open as a draft. I do like that so it doesn't fire off the CI. Who triggered it, that's nice. Did it� that's a link into the issue in Sentry. Very cool.

LAZAR NIKOLOV: And the changes are the ones�

JASON LENGSTORF: Changes are the ones that we would expect.

LAZAR NIKOLOV: We don't need to merge this one, if we didn't want to. It's in GitHub, here's a fix. You can edit it, if you wanted to, et cetera, et cetera.

JASON LENGSTORF: We is hit, "ready for review." Let's merge it. Let's pull it down. Let's get our fix, here. So, we're going to get "pull."

LAZAR NIKOLOV: Yeah, yeah. Unstage stuff. A lot of unstage stuff.

JASON LENGSTORF: Oh, got it. Got it. Got it.

LAZAR NIKOLOV: If you wanted to. If not, we can, like, skip it. YOLO. [Laughter].

JASON LENGSTORF: All right. Here we go. That pulls us back in and then we're going to run Docker Compose Build, it should go quick because we already set up all the services.

LAZAR NIKOLOV: We made a bunch of changes to the web. The PR opens and makes changes to the web. We're going to wait for Next.js to rebuild again.

JASON LENGSTORF: Okay. We get to blame Next.js. Any time I get to blame Next.js, I'm actually kind of happy.

LAZAR NIKOLOV: This time, as well.

JASON LENGSTORF: I hate fixing bugs. Same. Extremely same. [Laughter]. Ah, yes, file change, it needs to rebuild the container. That makes sense, I guess.

LAZAR NIKOLOV: We can leave it like this. We can try the dev stuff, but we don't need to because it's not [Indiscernible] so please don't� no, it might work. [Laughter]. It's there, for educational purposes. Yeah. So, we're going to wait, you know?
[Laughter].

JASON LENGSTORF: Yeah. Okay. So, this is� oh, what did you do� did you fail on me? Wait, this is different.

LAZAR NIKOLOV: Failed to compile.

JASON LENGSTORF: Use memo is called conditionally. Oh, no, did our bot screw us? Bot, ah! Let's look at what change got us.

LAZAR NIKOLOV: Use memo. There we go. It's after the "if."

JASON LENGSTORF: Ahhhh. Okay. So that's a problem.

LAZAR NIKOLOV: Yeah. The model needs to be stronger on React.

JASON LENGSTORF: Got it. We can fix this, though. Now we get to be developers and it got us most of the way there and we'll�

LAZAR NIKOLOV: No, not there.

JASON LENGSTORF: What page was it?

LAZAR NIKOLOV: App.

JASON LENGSTORF: Practice Flashcards and look for Use Memo.

LAZAR NIKOLOV: The "if" is, like, above there.

JASON LENGSTORF: Here's our "if." Okay. This, then, I think goes�

LAZAR NIKOLOV: Put it all the way down.

JASON LENGSTORF: It goes under the memo? The Use State, the Use Memo? There's a Use Effect? So that should work...all right. One more try...

LAZAR NIKOLOV: Our jobs are safe. [Laughter].

JASON LENGSTORF: I think this is part of the� it's also, I think, a good indication that we can't fully let go of the reigns and if we had reviewed the code more closely, we would have noticed that. It also, I think, points to having a better local dev environment so you can pull the PR down as opposed to yeeting it.

LAZAR NIKOLOV: I wish I fixed the dev container.

JASON LENGSTORF: You know, it's fine. It's fine. We've got a solid, like, 35 minutes left to get through these other seven features you wanted to show me. [Laughter].

LAZAR NIKOLOV: Going to get some coffee, maybe that will make things faster.

JASON LENGSTORF: Pour a little bit into the computer, just keep it going. [Laughter]. What's up, Nick. How you doing? Welcome in.
And I won't restate the container again, while we're going here. We'll let the rest of them be sort of hypotheticals, just because we want to make sure we have enough time.

LAZAR NIKOLOV: Maybe just one more time, but that's it.

JASON LENGSTORF: Sure. I'll let you make that call. I won't get happy with restarting things.
Database is ready.

LAZAR NIKOLOV: Okay. So now it's booting up.

JASON LENGSTORF: There's the Next. Let's try this again. Now we're ready to practice. I'm going to start and it's going to say...

LAZAR NIKOLOV: Drum roll. No flashcards.

JASON LENGSTORF: Instead of exploding, it works the way we want.

LAZAR NIKOLOV: We'll go to Walmart and add a bunch of stuff. There we go, issue number one, fixed.
Try to create a category for Apple employees or for Zara employees.

JASON LENGSTORF: Zara, like that?

LAZAR NIKOLOV: Yeah. Category created. There's no error. So, what would you do? Inspect element. Go to Networks and look at the requests, right.

JASON LENGSTORF: Yes. Okay. All right. So, we're going to�

LAZAR NIKOLOV: Create again.

JASON LENGSTORF: Here's categories. And it says� what's my response? Response, server error. Okay, why did we get a server error?

LAZAR NIKOLOV: The API breaks. But we don't know. You can consolelog, in this case. It's Django, they are getting errors in Sentry, but do they know the error is here, in this issue? How would you connect the frontend issue with the backend issue? They have their own project manager, their own priorities and stuff.

JASON LENGSTORF: And I think that this is one of the things that gets really challenging. I've worked in companies that are large enough to have lots of different services and when you hit this kind of problem, you� what I witnessed was people getting defensive and how that manifested is that we would look and say, we validated that we're successfully sending to your service. This is no longer our problem. And then we'd open an issue for them. We'd walk away and it would be up to them to figure out how it worked, if they needed reproductions on their side, we would eventually help them but it certainly wasn't a priority for us and it dragged� like, you could witness in meetings, if something crossed a service boundary, the whole place iced over and nobody wanted to talk about it. Nobody wanted to deal with it. This is� this is a very serious form of project slowdown. And the way that I would end up solving it, in practice, I would probably get on Slack, figure out who the owner of the service is, send them DMs and be like, we're getting errors, do you know why? I'm getting to the point where I have reported the bug and then I sort of wash my hands of it.
I'm hoping you're about to tell me there's a better way.

LAZAR NIKOLOV: Yeah, we're going to put the whole thing on one tray, from the frontend and backend and we'll see which backend error causes this frontend error. Right.

JASON LENGSTORF: So if I go back to my issues, we don't get anything here, although I do get to mark this one as resolved, tada!

LAZAR NIKOLOV: Let's select the Django one.

JASON LENGSTORF: We have good insight what's going on here.

LAZAR NIKOLOV: Imagine you have 99 other issues, you may not know this is causing the frontend issue. There's a self.name is less than 6. There's a validation and this is a validation mismatch between the frontend and the backend, stuff we usually hid. But we are going to put it on one trace because right now, it could be, you know, connected. You can have people, you know, getting on Twitter at your app saying, you can't really create categories and the app is terrible and no one should use it, et cetera. That might give you a little� a little insight into how you can start it. Or, you can actually go and set up feedback.
Let's going back to VS Code. And we are going to set up� we're going to set up two things. So, first, let's going to the Sentry Client Config and we're going to add the feedback configuration� feedback integration, next to the replay. So we got the replay integration. We're going to add the feedback.

JASON LENGSTORF: Ah, this one. Okay.

LAZAR NIKOLOV: Feedback integration. And this is going to add a fullycustomizable button.

JASON LENGSTORF: Is it one of these three?

LAZAR NIKOLOV: So this is going to add a fullycustomizable button. It's like an overlay. You'll see it. That's one thing. The other thing is if we wanted to start a custom trace, we could. Now, we're going to rebuild the project again. [Laughter].

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: We're going to rebuild the project again and we're going to see this� the feedback integration in action. What this is going� as I mentioned, it's going to add a little button in the corner of your screen whenever something happens, users will click that button and report the issue.

JASON LENGSTORF: Ah, I can show this. Look.

LAZAR NIKOLOV: There we go.

JASON LENGSTORF: If you see an issue on Learn With Jason, you can report a bug and this is using the Sentry feedback thing.

LAZAR NIKOLOV: Yeah. And this is basically going to tap into the trace, itself.

JASON LENGSTORF: Okay.

LAZAR NIKOLOV: And we connected the backend and the frontend so when the user leaves a bug report, that categories are not created, it will resurface that category not found in the Python project. Everything is going to be on one place.

JASON LENGSTORF: Okay. Okay.

LAZAR NIKOLOV: It's also going to have a session replay tied to that feedback so that you can see how the user used the app and even filled out the feedback form.

JASON LENGSTORF: And so the idea, here, is� just making sure I understand. I'm the user. I load this page and on Sentry's side, you're creating, like, a session for me, as the user. And then, when I go to create that category, the session that I'm using gets the error on the API side. But on the client side, there's no problem. Then, when I go to the feedback, my same session is intact and I say, this broke. Then what that signifies is that something happened that should group all this together so now my feedback, my client, my web app session replay and the API trace are all sort of associated as, like, there was an event here, something happened.

LAZAR NIKOLOV: Yeah, exactly.

JASON LENGSTORF: That's superclever.

LAZAR NIKOLOV: Let's go check out it.

JASON LENGSTORF: I'm out here.

LAZAR NIKOLOV: We have the new�

JASON LENGSTORF: Right. Right. Here's our bug. So I'm going to try to create Zara again. It says "category created."

LAZAR NIKOLOV: Optional name, optional email. The required one is the� the message. Like, tell me what you expected.
And, yes. Try yelling. Let's see. You can attach a screenshot if you wanted to. We're not going to do this here because there's nothing.

JASON LENGSTORF: All right. Okay. I've made my report.

LAZAR NIKOLOV: There we go.

JASON LENGSTORF: Angrily.

LAZAR NIKOLOV: As you should. [Laughter].

JASON LENGSTORF: Now if I come back out here� wait, wait. I go to "issues."

LAZAR NIKOLOV: We go to feedback. There are multiple ways to get to this, but there is User Feedback for us.

JASON LENGSTORF: What if I already did this? Do I need to add a thing?

LAZAR NIKOLOV: Do a little refresh. Now it should give you a minute�

JASON LENGSTORF: Okay. I just� I'm getting things out of sync here.

LAZAR NIKOLOV: I'm surprising that it didn't mark it as spam because, you know, yelling and profanity usually marks it as spam but I think you were gentle enough to be in the inbox. [Laughter]. This is� [Laughter]. This is the feedback. It's not just text. You get the session replay. You get the URL, where it happened, at the top, and can you scroll up a little bit?

JASON LENGSTORF: Up or down?

LAZAR NIKOLOV: There we go. See full replay. So we're going to see the full replay here, the whole session, even of you filling the replay, et cetera.

JASON LENGSTORF: Here's where I actually tried to do some stuff.

LAZAR NIKOLOV: Yeah. Tried doing that.

JASON LENGSTORF: Okay. Tried doing the thing. We got our note.

LAZAR NIKOLOV: Try to click on the trace. Let's see the trace. You can, like, make more room because this is going to be...big and also, like, collapse the sidebar. No traces found. Maybe this hasn't been, like, crunched yet or updated yet, so try going back to, uh, the feedback. There should be a trace. If not, we'll try again. Maybe it's, like, the  we do have that. We should have a trace, as well.

JASON LENGSTORF: Do I need to� ah, let's see. Full replay. Trace. Looks like we're missing that part.

LAZAR NIKOLOV: The demo gods are testing us. This is sending a post request to this� to post to "/API/categories." Let's go to Performance here. We're going to click on the Django project. Let's do this one. Go and find the post. There we go. Source API Categories. Go to Sampled Events at the top. This is going to give us the events that were triggered. So, let's pick this one, for example. These are all the instances. And this is going to take us to the trace view. We should have seen this, basically, but maybe� yeah, the data is not there yet. Yeah.
So, this is the trace view. This is that tray that has all the clientside stuff, all the serverside stuff on one, single screen. So, we can see, top to bottom, we loaded the Manage Screen, and we made the post here. There's a gap of nothing because we were filling out the form.

JASON LENGSTORF: We were thinking, the computer wasn't working.

LAZAR NIKOLOV: If you expand it, this is Next.js. Expand this, this is Django side. This happened on the server until this point, this is Next.js. But from this point on, this is Django.

JASON LENGSTORF: That's slick. That's really slick. Somebody's asking what the tool is. This is all being done inside of Sentry. We've installed Sentry on the Django app and the Next.js app.
As we're looking at this event, these are two separate properties, right, or two separate projects�

LAZAR NIKOLOV: Languages.

JASON LENGSTORF: But you know how to tie them together in the backend.

LAZAR NIKOLOV: Exactly. The this is console.log. The user's computer is somewhere in Europe or U.S. we can expand these� these things. We can expand them and, you know, there's grouping. You can see all the middlewares and now we see that the category name, too short, is caused when we tried to post on "categories. This is Django, so we'll report this to the backend team. We don't even need to. This happens when we do this. So the frontend is not working. Right. And because we do have that recording, they can see the session replay when they post on slash categories and see that thing at the bottom. We're going to optout of masking so they're going to see that there's a category created successfully.

JASON LENGSTORF: Say I'm in here, do I� can I get to that session replay?

LAZAR NIKOLOV: Let's see. We got the trace. We got the web vitals. Got the profiles and we're going to get into the profiles later. I'm not sure. We can do the opposite. Maybe we can...or we should...I don't know where it's linked, maybe it's on this one because this is the page load.

JASON LENGSTORF: Okay. So, yeah, maybe� maybe not�

LAZAR NIKOLOV: Not directly. You can go into the� we have the bread crumbs here. Yeah, maybe not directly but you can definitely go into the error and go from there. This is more for, like, you know, debugging the operation flow. You get the profiles here but we're going to talk about the profiles later.

JASON LENGSTORF: Cool. All right. So, this is�

LAZAR NIKOLOV: Connected the frontend issues with the backend issue.

JASON LENGSTORF: It is knowing how the apps work, you know, as the owner here, let's say I own the frontend, I can see, here is where I posted and I can see the error came from Django. We have proof the error's happening on the other side and come in here and say, we hit this specific error. I don't need to be on this team to know� this year, that's kind of a gamechanger for me, as a dev, because I don't own the service, I don't write Python but I can definitely see it's a problem.

LAZAR NIKOLOV: It means your team that works on Next.js application did not implement the validation.

JASON LENGSTORF: Or we need to say, hey, this validation is too restrictive, we need to relax it. Very cool.

LAZAR NIKOLOV: The dots are connected.
We're going to check out another error and this is going to be a bit more complex. It's not an error, it's an issue. We already have the data for it. If you go and reload the "/manage" page into the demo. Sample rate, I would say, like, 15% and start going up, based on your quota. I'm answering to Jacob now. Hit "refresh" and look at how� it should load pretty slow, right?

JASON LENGSTORF: Let me get the network tab up so we can see what's going on. We got something hanging. What took the time here?

LAZAR NIKOLOV: 4+ seconds. That should be the main request. Or it's not. Did I not post this? We'll see. We'll see. But, yeah, this is another� yeah, disable cache. Let's see. Honestly, Next.js� you know� did some hard times with the caching and stuff because I couldn't really showcase.

JASON LENGSTORF: This is some kind of a ping, right?

LAZAR NIKOLOV: Yeah. I basically planted a little flower into the "/manage." We should see it in Sentry now. Go in Sentry and we're going to go to� let's try Performance. And, we're on the web. Yeah. Let's skip right into this� this, right here. This is the serverside Next.js. This is too fast. It should have been 4+ seconds. Let's go in. Let's go in and see what's happening.
All right. We got categories and some flashcards. So I added a little slowdown to all of these. Ooohhh, okay. I got it. I got it. It was okay for you, not too shabby. Go back to the demo now. Go back to the demo. Trust me, it's worth it. We have no issues here. We're developers, we're pushing this to production, it's all good. Give it a second because it's using some LLMs behind to populate a bunch of flashcards. There we go. Hit this again. This is creating one category with a bunch of flashcards. There's a user that uses the app for a long time, they have categories, they have flashcards here.
It should not be this fast now. Try refreshing this page and see how long it takes to load.

JASON LENGSTORF: This is nice and slow.

LAZAR NIKOLOV: Should be nice slower now. 13 seconds. Oh, no, 4 seconds.

JASON LENGSTORF: 4 seconds to get to the meat of the page.

LAZAR NIKOLOV: If we didn't populate everything or do more flashcards, we can't really catch this issue because locally, we'll just create a bunch of flashcards because we're in a hurry. We'll just push them. No, there is actually a slowdown. Let's go back to Sentry. Let's refresh that page and go to All Events.
Go back to All Events or�

JASON LENGSTORF: All Transactions?

LAZAR NIKOLOV: Go to Sampled. You should see the foursecond one.

JASON LENGSTORF: Here it is. We got a couple of them in here.

LAZAR NIKOLOV: Now we see, oohhh, Categories is, like, 63. Look at flashcards. These are not crashes. If they're red, they're crashes. If they're blue, they're performance issues. Click on them. You should see something interesting on the right side. Click on the trace, here. Look at this one.

JASON LENGSTORF: N+1 query.

LAZAR NIKOLOV: This is one issue that the Sentry SDK figured out. It's an N+ 1 query. For each ID, give us the details. You can click into it. You'll see that this is an issue. But go back now. This is also the actual SQL that was executed. But go back and try to zoom into those N+1 issues. Go back to the trace.

JASON LENGSTORF: Here?

LAZAR NIKOLOV: No, like, back to the trace view.

JASON LENGSTORF: Oh, even further back.

LAZAR NIKOLOV: Try to zoom into these groupings.

JASON LENGSTORF: How does one zoom?

LAZAR NIKOLOV: It's like Command+.

JASON LENGSTORF: We can see tons and tons and tons of these.

LAZAR NIKOLOV: First of all, they're in a waterfall. Second of all, if you click on them and look at the query, first, we see a pages leap. Oh, interesting. Then we see select category, select category, select category.
Let's open the code, the API. Try to go there as fast as we can because I also want to demo profiles. This is something that can be�

JASON LENGSTORF: Okay. So, let's get into API and that was flashcards.

LAZAR NIKOLOV: Presentation, API.

JASON LENGSTORF: Here. Okay.

LAZAR NIKOLOV: And "get all flashcards." We can add customized implementation here easily. Getting to the "get all flashcards," this is queries, this is "repository.findall" here. Get into that. What is basically going to do is use the flashcard model that comes with Django. You give me all the flashcards. You aren't writing any SQL. But there's still some issues happening.
Go into the two entity list. First, we're getting all the flashcards and then we're doing a list comprehension here, which in JavaScript means a for loop for every flashcard, invoke this.

JASON LENGSTORF: Oohhh, yes, and that's a mess.

LAZAR NIKOLOV: Get into the two entity, you're going to see� oh, we got to go back. There's, like, a� this is the interface, we got to go to the flashcards mapper and look at this...we are requesting a category for each flashcard. So, that's the select category, select category, select category. If you didn't know this, you want to know how to, you know, debug this. Let's go back to Sentry now. First, you know there's an issue. There's a waterfall. So what we're going to do is click on the profiles here and we're going to select the� this one, the flashcards one. So, here's the profile. Right. The profile is like tracing but instead, on every 10 mill seconds or so, it captures a stack trace. You can see what executes without manually instrumenting it. So, I'm going to grab the mouse here. These are all of the, um, selects. You see them?

JASON LENGSTORF: I see them.

LAZAR NIKOLOV: At the top. If you scroll down, the red� the red stuff is from the server. We got to zoom out. We got to do...scroll all the way� the blue stuff is from our code.

JASON LENGSTORF: Got it. Okay.

LAZAR NIKOLOV: There's a lag.

JASON LENGSTORF: There is, yeah.

LAZAR NIKOLOV: Blue stuff, our code; red stuff, Django. We went into the flashcards, we went into the query. We did the model mapper interface. We did this, but I want to zoom in even further because there's one more blue span that I want to show. This one. This one says, delayed execute. And you see what it is? It's repo wrapper. So there's a delayed execute after we call the compiler, the SQL compiler. So, this is what's causing that little slowdown. If you go to this file, you'll see, just, like, try "_cursorwrapper."
So, there's that select. If we delete this, we'll just say, cool, we solved that issue. But, yeah, this is how we found that this is� this is where that code is coming from, using the profiler. We didn't do any custom implementation. When we saw the� let's go back to Sentry. When we saw this thing, right here, above is the transaction and below is the profile. So first, we see DB Connect. Xaxis is the time. So we first connected to the database and got all the flashcards and then we have a repeat of select categories, select category, select category. This is the source. I can't really hover on this. You see the source, right?

JASON LENGSTORF: Yeah.

LAZAR NIKOLOV: If you go there, we actually went there on line 9. Can you go to the flashcards mapper, try searching for that. This is the last thing�

JASON LENGSTORF: Was that repository mapper? Database Repository Mapper, Line 9.

LAZAR NIKOLOV: When we are invoking the category entity, that's when we are creating these� these repeated calls. So, basically that is making an additional DB call, which is causing that, you know, waterfall to happen. So, in order to refactor this application, we could pull the category out so we don't really need to nest it here or put a category ID and the client can get more info on the category ID and it's just going to be one, single DB call. That was the second DB span, "Get flashcards." And waterfall's going to be gone and infinitely faster. So, this is profiling now.

JASON LENGSTORF: It's slick and it's definitely one of those things that� how  like, how to get visibility into something like this because, you know, these sorts of charts are really intimidating to look at. But the color coding knowing this is our code, this is system code. We wrote this, right. And this kind of showing up is, oh, that's a little thing that we wrote that we maybe wouldn't have thought of because it's buried in system code, that's a hell of a spot, right. It gives us places to look.
So, yeah, this is� this is great. Six minutes left, anything else you wanted to show?

LAZAR NIKOLOV: These are the tools that, you know, can help you debug complex applications, even for issues you don't know exist or issues that are caused from one space, but they erupt from a different space, you know, multiple type of situations or no crashes, your app is just slow. We use the profiler because in order to use the tracings, you have to know the spans. It instruments out of your code, the thing that can be instrumented, but you can manually instrument it but you're not going to instrument the cursor wrapper because you don't even know that file exists, for example, right. So if you want to really zoom in, that's when we use the profiler and Sentry basically puts all of� everything into one, single trace. That was the session replay, the recording on the UI screen. The slowdown, the metrics, I didn't even touch web vitals and stuff. There's a whole different side to the product itself. But, yeah, you get the profile. If tracing isn't enough and you really want to dive deeper into a function level, you already have the trace. There's already a profiler on it if you configure profiling, so make sure you turn it on. You get into it. This is how you debug complicated situations, everyone.

JASON LENGSTORF: Really good work. I mean, it's just nice to use. Like, I like it. It still can be a little overwhelming because this is complicated stuff. There's a lot of UI here. Having a path on how to solve something when you get into code that's outside of your team's control, there's really� it's hard to imagine a way that that gets easier than having something where you've sort of got this full display of, here's what happened in the app, here's where the code happened. Here's what the� how things moved through. Here's a replay of the user having the issue.

LAZAR NIKOLOV: And rageclicking.

JASON LENGSTORF: Will that show up?

LAZAR NIKOLOV: It should, yeah. If I see an envelope going sent...you got to go to� you got to wait now.

JASON LENGSTORF: Yeah, where would I look for that? Would it be Issues?

LAZAR NIKOLOV: Yeah, we also get rage clicks. It is connected to the session replays. If a user clicked multiply times� if they click multiple times� I think there needs to be an element, or something like that.

JASON LENGSTORF: I was clicking on nothing.

LAZAR NIKOLOV: I don't have that in this demo but I'm going to add it for next time. We can give you rage clicks. When people click on elements seven times in five seconds� I don't know what the formula was.

JASON LENGSTORF: You click it, what was that.

LAZAR NIKOLOV: It's not working. [Laughter].

JASON LENGSTORF: You sent me a link for how people can get started, so I'm going to throw that up on the screen here. Go here, sign up here. This is good for a handful of reasons. If you're thinking about trying this, sign up through this link because it shows that, you know, the stuff we're doing works and it makes companies want to continue working with me and, you know, Lazar gets his next promotion, all the things we want to happen. If you're thinking about doing it, that's the link for you.
Let me put it up on the screen here. For somebody who wants to go further, where else� like, what resources should they hit?

LAZAR NIKOLOV: Docs, dig into tracing or profiling. There's� we got a lot of pages on the docs, for everything out there.

JASON LENGSTORF: Get into the docs. The docs� in the docs, they're linked from everywhere, right?

LAZAR NIKOLOV: Yeah. You can also join our Discord server because our engineers are there. If you have an issue with the SDK.

JASON LENGSTORF: Where does one find this Discord? Down at the bottom. Drop a link to that, as well. Yeah, and let me do another shoutout to go follow Lazar on Bluesky. And I will do another shoutout to our captioner. Vanessa's been here all day, doing the human captioning, which I very much appreciate. You can find it at the URL that's scrolling across the bottom of the page. That is made possible through the support of our sponsor, we've got Tuple, that's what we've been using all day and it sounds like our timing is great because it's about to get loud in the studio. [Laughter]. So with that one, Lazar, any parting words before we shut this one down?

LAZAR NIKOLOV: Damn. I'm bad in situations  I don't know. I was thinking about this whole workshop and I don't have any parting words. Thank you for watching.

JASON LENGSTORF: Thanks, y'all, for hanging out. Check out the schedule. Make sure you follow the show on� you can like and subscribe on YouTube. You can follow on Bluesky. With that being said, thank you all, so much, thank you, Lazar, for taking some time. This was a lot of fun. From me, my beard, Lazar and Lazar's beard, have a great day. We'll see you next time. [Laughter].

Learn With Jason is made possible by our sponsors: