 Everybody, it's Brian, and in this video, we're going to talk about the QDebug class. We've touched on this before and we've even worked on it, but we haven't really explained why. Digging through the documentation, it simply says the class provides an output stream for debugging information. Now, you may be seeing debugging and getting confused and thinking, oh, this is a debugger. No, it absolutely is not. It's simply an output stream, and it uses QIO device. Here from the last video, anything that does input output in Q uses QIO device as its base class. So clicking more information gives you more information, but it doesn't really explain why you should use this. What is the big deal here? So you'll see different things like Q warning, Q critical, Q fatal, but you got to kind of dig through the documentation here. The big takeaway is that this will automatically format your data and you can turn on different levels of verbosity. So what we're talking about here is logging. Let's take a look at this graphic here. So in normal C++, we have the standard out or the standard error, and that can go somewhere. Either the console or a file or you can use it as input for another application, whatever you want to do with it. Q debug sits kind of in front of that. And when we say Q debug, we're actually talking about a whole subset of an up type. So we've got debug, information, warning, critical, fatal, and system message, which is also a critical. So there's some general things you need to understand. So debug is meant for you, the developer. Information would be information you would display to say the end user. A warning is very self-explanatory. You're saying, hey, something's probably bad going to happen here. Critical and fatal often get really confused. So critical would be something like, hey, the file does not exist. Can't continue. You need to give me the file where fatal is saying, hey, cannot divide by zero, something that would just crush your program. So you need to be a little bit careful on those two. And also, the major takeaway here is you can install what's called a message handler. So you can intercept those. So it doesn't matter where in your application this is. As long as you're using Q debug, it will always follow this same chart. So you can have it in 30 different classes, and you can do a global message handler, which will intercept every single Q debug message going out of your application. And they conveniently have the snippet of code, which we're going to copy, paste, and test out. First thing we need to do is some initial setup. So I'm going to copy and paste some code in case you're wondering where I'm getting it. We're just going to look up the Q install message handler. It's baked right into the help file. And we're really just copying this code here, but it's a little small on that screen. So I'm going to get rid of this. Let me bring it up here. So this is what we're going to grab. We're just going to copy it. Notice it's going to take a minimum of Q application, STD IO and STD lib. We don't really even need those to be really honest. Let's flip back into our file. Our code has got Q core application, Q debug, Q tech stream and IO stream, and we're using namespace STD. Don't really even need any of that. But just for sake of brevity, we're going to put it in there. So at a minimum, what we really, really need is a function that has this format, a message type, a log context, and a string because that's what we're really looking for when we go to install this message handler. Now, I also want to put in a simple comment here. This is the only modification we're going to make to their code, which is a comment. Because we can intercept this from anywhere in the app, we can log to a file or system log or whatever we want to do. So everything in the application is going to go through this function once we install a message handler. Other little snippet of plumbing that we're going to do here is we're going to go down into our main and we're just going to copy and paste some code. And if we don't like the formatting, I just control a right click refractor. Oh, sorry, actually it is auto indent selection. There we go. And this is extremely simple. We're going to take a Q tech stream, call it Q in, which is going to wrap around our standard input. But then notice we're using C out, we're actually using the standard library. This is just to show that we can actually do this outside of Q to bug. But the moment you use the standard output, it's not going to get logged. So for example, we're standard outputting enter a command, start, stop, test or exit. So that's what this loop is going to do. While we're running, we're going to continually ask the user for some sort of command. Then we're going to use a Q info you entered. And because we're using Q info, which is part of Q to bug, it's going to be captured by this message handler. If you're ever kind of confused here, look at the different message types. It starts with QT and then whatever and then MSG. So you got debug and then info and warning and critical and fatal. We've covered all those in the introductory part of this course here. So let's go ahead and look at how we would set this up. Okay, this program does absolutely nothing. What we want is for every time we use a Q info Q debug or Q warning that it goes through our message handler here. But to do that, we have to install the handler and we use a function called Q install message handler. And notice it's looking for a Qt message handler, which is actually a type def towards a function that has this signature. So this is literally just a function pointer. I'm going to grab this. And it's that simple. You just simply give it the function name and voila, it'll work. Now I'm going to do this a little bit differently here because we are using Q text stream here to get some commands. I'm going to wrap this around and say, all right, if the command to upper equals start, then go ahead and install the message handler. So we know how to install a message handler. And now from this point forward, anytime we use a Q debug or Q info or Q warning and so on, it's going to go through that message handler called the my message output, this big function that we copy and pasted, but how would we uninstall that means stop using this. So I'm going to select Q install message handler hit F one and let's dig through the documentation. And it says to restore the message handler call Q install message handler with zero. So basically you're just zeroing out that pointer. All right, it's very, very simple. You just do something like this. If the command to upper equals stop, then we're going to call Q install message handler zero. So we're just simply setting the pointer to zero. I almost wish they had a separate function called Q uninstall message handler with no parameters, but it is what it is. So far, we have done setup, we've installed it, we can also uninstall it. Now we need to be able to test it. And this is where, well, things get a little bit confusing. So I'm going to slow down just a bit. And I'm going to copy and paste a function here called test. We have Q debug, Q info, Q warning, Q critical, and all of them just say test. And then I have Q fatal commented out. Notice that we'll talk about that when we actually run this thing at the very end. But I just wanted to highlight that it's commented out for a reason, special note on that. Okay, so the thing about this handler here is it's going to capture everything. It's going to intercept it from anywhere in your application. Doesn't matter where it is. So it's going to pick up, and let's just scroll down here. It's going to pick up this Q info in the main, and it's going to pick up all of this stuff and test. I've also added a class called kitten. You'll notice it's a Q object, but it doesn't necessarily need to be one because it's going to use, you guessed it, Q debug in this specific case, Q warning, which is going to say I am hungry because kittens are almost always hungry. The thing I'm really trying to drive home here is it doesn't need to be in the same file. It can be a completely separate part of the application that doesn't even know this message handler has been installed. So let's go ahead and add our kitten in here. And of course, just in case you're wondering, yes, you have to make sure that it is in your CMake for it to show up in your projects. Once we've got that in there, let's go down to our test and let's just put it right here. All this kitty and we'll say kitty dot meow. So now our test function is going to have some in there, but also we have a class and if we just right click and go ahead and follow symbol under cursor or you could just hit F2 on the keyboard, it's going to take you right to the function we're calling. It's going to use a Q warning. So all of that is baked right into our simple little test function. Now to wrap up our testing, what we're going to do is just say, hey, if the user enters a special command in this case, test, we're going to call that test function up here, which has all of that in there. Okay, to wrap this up before we actually run and test this thing is we need to give the user the ability to exit this loop. Very simply, I'm just going to say, if the command to upper is exit, I'm going to set our running bool to false. So of course, it'll just stop running. You could use a breaker, however you want to do this, it's really just a design choice of whatever you want. But our major commands, just to recap our start, stop, test and exit. Start will install the message handler, stop will uninstall the message handler, which is a little deceiving because we're saying Q install message handler, but we're saying zero for the pointer. Test is going to call our test function, which has, well, you guessed it, all of that goodness baked right into it. And we're even using a class just to demonstrate it can be somewhere else. And then exit, of course, just sets our flag and jumps right out of there. One last little thing I want to do is I want to know when this loop is done. So we're going to see out finished. Notice we're doing see out. This is going to really demonstrate that when we use see out, it bypasses this message handler altogether. There's really only one thing left to do and that's run this bad boy and let's see what happens here. So starting our application, enter a command, start, stop, test or exit. Well, I'm going to not start first. I'm just going to do test. And it says you entered test. And then we just see test, test, test, test. And I am hungry. Well, okay. Well, clearly this is the cat, but what are these? It just doesn't tell us. It's just doing a standard output. Okay. If we look at our code here, you can see we've got some formatting for each one of these. So we can tell right off the bat, it's not installed. Our message handler is not even installed because I skipped the part where I say start. Instead, I just went straight to test. So let's go ahead and do an exit. Just to make sure that works. Okay. Good. It did finish. We're going to run this a few times just to really break this down here. Remember, when our message handler is installed, you're going to see all of the special formatting for each one of those. Let's go ahead and run this again. And this time I'm going to say test, exactly like it was before. But I'm going to say start. It doesn't look like anything happened. But if I say test again, voila, it's now suddenly different. Your message handler is installed. If you look at this, this is incredibly cool. So we have a info, you entered, and then it has all that in there. It tells me everything I need to know. This is almost perfect for a logger. It tells me the file. It tells me the function. It tells me what it was where there was an info, a debug, a warning, a critical. And then of course you can even do in different areas. So for example, here's our kitten class. The kitten class isn't even aware that the message handler is installed, but it still captures it. So think of this almost like a global capture system or a logging system. Of course you may run into some thread issues, and we'll talk about that in future videos, but whenever I get asked, how do you build a logger and cute, this is how you use the install message handler. All right, that is incredibly cool. So let's just do test again. Okay, works as expected. Now I want to uninstall that message handler. So I'm going to say stop, and it says you entered stop. It looked like it still goes. But if I enter test again, you see the message handler is no longer installed. We're right back to the plain old standard output using queue debug, queue info, queue warning, and so on. That is extremely cool. So you can now install and uninstall the message handler at will. Now I want to wrap this up with one special little note. Remember, we had queue fatal commented out. And this is specifically going to say fatal message, not test, test, test. So let's rerun our example with queue fatal uncommented, and let's see what this does. So I'm just going to say test and notice as return to close this window. A lot of people get confused and go, no, wait a minute, did my program just crashed? We crashed it using queue fatal. We have to be a little bit careful when using queue fatal for this specific reason. It will just unapologetically kill your application. And let's close that. Rerun it. Let's go ahead and start this. And let's say test one more time. And you can see it did capture that it was a fatal message. And it tells us exactly where it is. So in case you're really wondering the difference between critical and fatal, critical is saying, hey, something bad really happened. Capital says something bad happened and it was so bad, I can no longer continue. And I would caution you from using a queue fatal without a message handler installed because you simply won't know what happened or where it happened. I hope you enjoyed this video. You can find the source code out on github.com. If you need additional help, myself and thousands of other developers are hanging out in the VoidRome's Facebook group. This is a large group with lots of developers and we talk about everything technology related, not just the technology that you just watched. And if you want official training, I do develop courses out on udemy.com. This is official classroom style training. If you go out there and the course you're looking for is just simply not there. Drop me a note. I'm either working on it or I will actually develop it. I will put a link down below for all three of those. And as always, help me help you smash that like and subscribe button. The more popular these videos become, the more I'll create and publish out on YouTube. Thank you for watching.