 So I'm going to go ahead and get started. Hi, I'm Colleen. I am a software engineer with Google. I have been at Google for a little over a year working on open source integrations between Cloud Foundry and Google Cloud Platform specifically. You might have seen my talk last year here, where I live action open source the GCP service broker. But today I'm going to talk about Stackdriver and Cloud Foundry. So the reason I'm giving this talk is I was in Santa Clara at CF Summit a few months ago. I gave a talk featuring some of our machine learning services available through GCP and through the service broker. And I just kind of touched on the Stackdriver debugger in that talk to my surprise, almost all the questions I got afterwards were about the debugger because, frankly, it's really cool. So I thought I would give you guys the deeper dive into this tool set. So Stackdriver, in general, is a suite of logging, monitoring, alerting, debugging tools provided by Google. And the really awesome thing is the Stackdriver debugger is now built into the Java build pack. So you're going to be able to debug your applications as easy as create service, find and service, restage application. So what do you need to make this beautiful dream a reality? You need a GCP project and some kind of login, either for the Cloud Console or all of what I'm going to show today can be done just through the G Cloud CLI. And you need at least Cloud Debugger user permissions. You need basically any modern version of the Java build pack. Version 3.15 was where this change was introduced, but that was released back in April. So hopefully, you're all already caught up to date. You need the Cloud Foundry service broker for GCP and, of course, a Java Cloud Foundry application. I'm going to show an optional integration if you're using the Stackdriver logging nozzle. You'll be able to see your logs in the Stackdriver logging UI. But if you're not using that, you can see them in just the standard out CF logs or whatever logging aggregation tool you're using. So the main features of the Stackdriver debugger are debug points and log points, both of which are dynamic, historic, and filterable. Debug points are also shareable, which is pretty cool. Who's ready to see an example? Everybody, hopefully. So this code is available online as part of the service broker repo inside the examples folder. And what this application does is it scrapes the aw subreddit. If you're not familiar with Reddit, it's just a forum. And this particular sub forum posts pictures of adorable animals, usually. So scrapes that, grabs the pictures, runs them through the Google Vision API to categorize them, and then presents them in this lovely UI. So I have my application already available on Cloud Foundry and bound to a storage bucket. But I'm going to create an instance of we have the Google Stackdriver debugger available as a service. So I'm going to create service Google Stackdriver. And then we're going to find service. And we're going to restage our application. While that's working, I'm going to pop out to the debug UI. So you can see we don't have any applications available to us to debug at the moment. As soon as our app restages, I'll refresh. And we'll be able to see our app show up. The debugger documentation, by the way, is available at this nice, easy to remember URL, cloud.google.com slash debugger slash docs. See if we're restaged, almost. So now we can come back here and refresh. There we go. Took a minute. So when you're viewing your application in the Stack Driver debugger, you can view your source code in a variety of ways. You can just select your repo from GitHub or from a cloud source repository. I made a change so that we could see some ways to use the debugger. So I'm going to select local files as my source. And just upload the code really quick. And then we can navigate through. And I'm going to pop into the Reddit scraper. So you can actually see the snapshot and logpoint history that I already have. So I've set a snapshot breakpoint here. That code might be a little hard to read. How's that? So I've set a breakpoint right after we find out what the label is from the Vision API. And I've also added a logpoint. So I'll show you how the snapshots work first. So you can see this says, waiting for snapshot to hit. The running application will not stop. So again, you have a production application running. You've restaged it. And that's all you have to do. From then on, you can add and remove these debug and log statements without having to restart your application. I don't know how many of you have been in this situation. I certainly have of needing to debug something and realizing, oh, shoot, my production application doesn't have the log statements that I need to be able to debug this problem. So then you have to go through and redeploy your whole application just so that you can get logs. And sometimes by that point, the problem has already passed. And it's just hard to track down. So this is really great for just adding those logs quickly on the fly. So if I go to slash reddit, that's going to trigger the scraper. And then as soon as we hit this debug point, I should. Oh, do I have? There we go. I think these are historic. I'm going to add a new debug point and try to scan. There we go. So we hit this execution statement. And at that point, the debugger just grabs a snapshot of your call stack, all of your local variables, and just dumps it to the UI and also saves it in your snapshot history. So we can see in here, we have URL with the labeled dog. We can come into the image, the image source. Let's go see what it has. That is indeed an adorable dog. And like I said, these snapshots are filterable. So we can add a condition here. So the way we're going to do that is we're going to say if label dot equals cat, and then restart this. This is going to filter dynamically to only hit when we get the specific label. So instead of just capturing that first hit or waiting until we hit this specific condition, which can be really useful in debugging if you have a situation that only comes up for certain inputs, you can also use expressions. If you want to compute something at runtime, a way to use this is either for some kind of computation that maybe you don't want to do on your own to pull in a bunch of variables or even just to simplify like drilling down into six layers deep of this sort of thing. So say, though, we want to see what all of the labels are. Like I said, when we are using snapshots, we're just getting the first time that you hit that execution statement after you set up the snapshot. So I'm going to come in here and I'm going to edit this log point so that we can have a new one. Say, hi, summit. OK. Then generate some data for us again. And then you can see when we come into logs here, wants us to use the Stackdriver Logging UI to view the logs. So we'll do that. We're getting global logs. And we can see our log points in there already. Let's filter by hi, summit. We can get a little better view of them. OK. So now we can see all of our logs for each time we hit that break point and maybe get more detailed information about whatever problem we're looking for. So pretty cool. We haven't actually debugged something. So maybe let's try that. So this application, when I come to the front page, you can see that these labels are links. When I go to this link, it should pull in all of the pictures of dogs that we have. Looks like we have five. Oh no, there's nothing there. Whatever could have gone wrong. I'm sure I don't know. Let's go look at view images, though. So let's take a snapshot again. Let's remove our condition. And actually, let's add label. And I'm going to ask that if you see my very obvious break in the code that you keep it quiet just for now for funsies. So if we add a label that equals dog, then we can restrict to just the endpoint that we're currently looking for. So come in here. And so just in case you didn't catch what the code is doing, it's grabbing all of our objects from our storage bucket, iterating over them, and saying if the image label equals the label that we're looking for, aka dog, then add them to the list to return. So we refreshed. And we never hit our debug point. That's so very confusing. So let's take a look at this log point that we have. Let's say, OK, let's compare the image label and the label that we're looking at. And so if we come out and we'll do, I'll make this a lot bigger, too. Let's do a CFLogsOvision so you can see how this looks just in your regular standard out. And we'll refresh this again. Come out, come back, terminal, come back. There we go. So we saw what we refreshed now. We got this dynamic log type. And we have the image label. Image has not been uploaded yet. And label dog. That's reasonably confusing. That would make sense. That's not the issue that I was looking for. So I'm actually a little confused about that. Let's, in fact, I said live action. Let's add a new snapshot point here and come back and see what we get. OK. So we have an image. Images is an empty collection. It's confusing. This did not happen in my practice. And confusing because we still have images. Yeah. Object says things. Oh, thank you. I was looking at images, not objects. So an actual, we're looking at this. Or we're looking at object is we have a storage object. So I'm going to go ahead and do the fix that I was thinking of. And we'll see if something is going moderately awry or it's OK. So at this point, I will open it up to does somebody see the obvious error in the code? So I kind of hinted at it with my snapshot condition. I have a label.equals here, but an equal equal here, which in Java is not going to match dog to dog, in fact. So what I'm going to do is I'm going to grab this code path and modify the code. And we'll see if this fixes our problem. So there is a recent change introduced into the build pack to simplify viewing versions then Stackdriver. So I'm going to come in and set a specific CF environment variable that says the application version. You notice out here, this says Awvision1. I'm going to set Awvision2 and repush my application. While this is running, I'm just going to showcase the LogsViewer a little bit more. So LogsViewer is pretty great in that we can also add filters directly from the log messages themselves. So if we want to filter to event type log message, we just show matching entries, pretty great. One other thing I wanted to show you was the shareability of the debug points. So I'm going to come back into my snapshot history to do that. So remember, we captured this snapshot here. So I can literally take this URL and copy and paste it. And I get the same snapshot history, the same call stack, and variables at this point in time. So if I'm debugging something that maybe I'm not the most familiar with, I can send it over to a colleague and say, hey, I know that you've worked with this code before. And maybe you can help me out. Here's what I'm seeing. And they can maybe jump in and help. And this snapshot history is shareable for 30 days. This log point history is going to stick around for 24 hours. So I bet we're up and running again. Let's see if my fix worked. It did. Yay. OK. Cool. So that's pretty much what I have to show you. I am sure that you have questions and I have answers. So number one is probably how does it work? This seems like magic, Culling. So the build pack contains an agent that basically gets triggered by that buying service call. If it sees the credentials available for the Stackdriver debugger, it's going to start the agent and then listen for these debug points and log points on execution. And that seems maybe complicated. And like it might add a lot of overhead. That really is what we found. So the engineer who actually implemented this integration did his own performance testing and found that it added about 1% to 3% of overhead. And so 1% to 3% just to have this option available to debug critical production errors seems like a pretty good trade-off to me. It is not available currently with any languages other than Java. We are actively looking for help adding this to the Python and go build packs. But it does work on other IASs. So your applications running on AWS, that's fine. Like any other service provided through Service Broker, it's totally cloud agnostic. You can still have your logs and your debug points go into the GCP UI. But you might want to consider running your apps on GCP because Stackdriver debugger is available for free for any apps running on GCP. The logger is a little more expensive as is debugging applications running on other IASs. But it is a pretty great added bonus if you happen to already be running on GCP. So if you need more information than what I've provided, obviously our docs are fantastic. You can hit me or my manager Eric or our resident Stackdriver expert Jeff up on Twitter. And with that, I will say thank you and open it up for any additional questions. There is IDE integration for the debugger when I don't know. I assume that it would also work with Cloud Foundry. So the debugger independently has IDE integration, which is somewhere in our documentation. So you should check that out. And that would be interesting to see if that also works with Cloud Foundry applications. In the back, it's going to bring you a mic. Will these Stackdriver Service Broker require SSH connections to be enabled? I'm sorry, can you repeat the question? Will the Stackdriver Debugger Service Broker that we have, will it require SSH connections for the Tomcat instances to be enabled to do this debugging? I'm still kind of missing the last part of your question. What about connections? I'm saying that this debugging that it requires to do, will it require SSH connections on the Tomcat instances to be enabled? SSH connections. It does require a network connection. And I don't know what protocol that's using. It's basically using, it uses the same protocol as other remote debuggers that you've seen. It's just a different method. Basically, it operates off of pushes from the remote debugger instead of creating a new connection every time. So, but I'm not unfortunately familiar enough with remote debugging in general to know what protocol. Sorry. Can you debug multi-threaded applications? My guess would be that you can, but I don't actually, I would suspect that it would pick a random thread of execution to do the snapshots, just whichever one hit that statement first. Again, it is very similar to other debuggers. So, whatever you're used to as far as debugging multi-threaded applications, it's probably matching that behavior. Yes. So, if the source code isn't up to date, I think you, I don't actually know how that, we can try that out, in fact. So, let's see what happens if we go back and modify this file to reintroduce the bug. So, now if we try to select a new source, say, we'll say add source code, okay, did that. Okay, so now we have wrong source code. So, let's see what happens if we add a snapshot here. So, it looks like it's just ignoring our snapshot, but it knows that this source code is incorrect. And I'd be curious to know if we add a snapshot here where the code still does match, do we get it? We don't. So, it looks like it's, this source code is incorrectly mapped. Oh, the other thing is we, sorry, we rebound to a different application with OVGEN 2. So, let's try that. That was actually probably the reason. So, now let's see if we add this. So, it's still hitting it. So, looks like you'll still get the statement execution for, I think because part of it's triggered off of line numbers. So, it's probably saying, it's probably giving you the information for line 58 anyway. As far as what would happen if you picked a line number that, so I think you would, if your code was completely different and you still had it correct, that line number still existed, I think you would get that snapshot. But if you put in a line number that didn't exist, I would expect it would just never hit. Yes. Yeah, let's find out. So, I think, yeah, it's running against the current code. So, you will want to make sure that your code is up to date in the viewer because this is going to be very misleading if there isn't a bug or you think there is or if there is a bug and you think there isn't. That was... Are there any other questions? Yeah, hi. Are there any plans to roll this out for like Node.js? Uh-huh. Sorry, do you say is there going to be support for Node.js? Yeah. Yeah. Stackdriver, I don't know if there's a Stackdriver agent available for Node.js. And let's go ahead and look and see what... So, okay. There is a Node.js debugger agent. It's in beta. So, we'll add that to the list of... And Ruby, to the list of volunteers to look for adding that to that build pack. Yes. Support for what replacement? Oh, I see. Support for code replacement. I don't know that might exist in the IDE integration, something that you could do relatively easily in the UI is to use the expressions. So, if I had had this break point and put in the expression image.label.equals label, you would have been able to see right away that that statement would execute differently than what you were seeing in the snapshot. So, you can at least mimic single statement changes that way. As far as actually changing it in the IDE, if that is something that you're currently able to do with Cloud Foundry, then it will probably work. If not, which I would be surprised with Cloud Foundry if you could do that without restaging. Any other questions? I think I'm out of time. Everybody's gathering like I may be out of time. OK. I'm going to be down in the Google booth as will some of my colleagues who can help answer more questions. If you have them, thank you so much for your time.