Lesson Description

The "Adding a Logger" Lesson is part of the full, Build a Fullstack App with Vanilla JS and Go course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano discusses two options for creating a logger: using a cloud-based provider or creating a custom logging system that writes to a file. He demonstrates how to create a logger package in Go and explains the design pattern of returning two values (object and error) in functions that may trigger an error. Maximiliano then shows how to initialize the logger in the main.go file and use it to log messages and errors.

Preview
Close

Transcript from the "Adding a Logger" Lesson

[00:00:00]
>> Maximiliano Firtman: So we are building an app, and we want this app to be a real-world project. And on most real-world projects, we need to deal with the real world. And the real world means things happen all the time, and we need to debug those things. So even if everything works fine in my computer, when I deploy that to a server, anything can happen, mostly when we are in the cloud and we have a lot of users accessing, for example, that back end.

[00:00:33]
So it's actually really important to always have a logging system to log problems and errors. I mean, it's not mandatory, we can deploy an app without logging errors and problems, but the day we have a problem, the day someone is sending us an email, the customer is saying, hey, it's all working.

[00:00:54]
The server is down, the website is down, it's gonna be difficult to actually tryi to find the solution quickly. So we need to think before hands and one way is to create a logger. Okay, there are many ways to create the logger, I mean, you can from go, let's go to main.go, I could go here and just use format font, print line and say, print line survey the files.

[00:01:28]
If there are any problem, for example, here I'm using the standard log system, but the standard log system is just saving, it's sending this to the output console. Or actually to the output of the operating system, that it can be a file as well, but by default, it's a console.

[00:01:47]
But from a server point of view, it's difficult to follow that. So where can I see the console of my server if I'm deploying this to the cloud? There are some solutions, some cloud-based solutions such as Burcell that will let you go into a panel and see the console output of your scripts, that sometimes is difficult.

[00:02:11]
So that's why we have other options. There are two options, we are going to pick one. One is to use a cloud-based provider, there are services that will let you send your logs to a server, and they have nice dashboards, then you can see all your problems by time, by hour, by device.

[00:02:37]
Okay, so some or most of those services are paid, so you need to pay for that. Or we can just create a log system, a very simple log system that writes you a file that this is how logs in the operating system typically works. So every error every problem that you have, it creates a new entry in that file, okay?

[00:03:01]
Of course we can use the database as well, but a file will be good enough. So that's why I'm going to create a new package, remember, packages in Go are just folders. So I will create a new package with the name logger, and if you're following along with instructions, this is a2.

[00:03:22]
So from readme,
>> Maximiliano Firtman: On a2, this is a logger, and then in the package, I'm going to create logger.co, this is probably one of the exceptions. We're not going to code manually this, it doesn't worth the effort, and it's a waste of time to actually take 15 minutes to do this.

[00:03:53]
So this is one that I will just copy and paste, and I will explain it. It's actually pretty simple.
>> Maximiliano Firtman: But at least we are not wasting time with this, that is not the core of our project, it's just a logging system. So new logger creates a logger is not really complicated, and then we have some functions there doing some things.

[00:04:14]
So on a structure, it's kind of simulating that, it's called the logger. It's a logger structure that actually will have like a file where we are storing this and we have two loggers. It can be an info logger and error logger. So because we can just send info messages, this is like console log in Javascript, or error messages like console error.

[00:04:41]
Then we have the new logger, this is the factory. Remember in Go we don't have constructors, we don't have objects, we don't have constructors. But we simulate the idea of a constructor through a factory, so the factory has a prefix new, okay, and the name of the value that we are creating the structure.

[00:05:03]
So new logger creates a logger is not really complicated, and then we have some functions there doing some things, and what's the idea? We are just opening a file, so we are saving this in a file, okay, that's all. And why am I doing this right now, because I will start coding my server, and there will be moments, many moments where errors may happen.

[00:05:35]
I should already have the logger ready so I can write to that logger at that moment. If I do that after coding my app, I will probably miss a lot of places, a lot of moments that I'm not logging. Yeah, you can also add a mark to-do mark and then replace all your to-do marks if you want, but that's why beforehand it's a good idea to set up your login system, okay?

[00:06:04]
And the great advantage of using a login system of your own, your custom login system, is later you can change that. Let's say that later you want to upgrade your login system, and instead of using a file, you want to use a cloud-based provider. Just go here here, change here, I know your app now is ready to load into the cloud, okay, makes sense?

[00:06:27]
So that's my logger, and now we need to go to main.go and update or create the logger actually, because we are not actually creating the logger. So we are going to create here a log instance, we can call log instance, that is going to create the logger, and we can create the logger here, or we can create a function, another function, initialize logger, for example.

[00:06:58]
And then we can call that function, it is giving me an error because the function is not returning anything yet. And then I'm going to create that initialized logger that will actually return a logger.
>> Maximiliano Firtman: You can see that when I added this, now I have by import as well.

[00:07:29]
It's importing this from a different package because the logger is in a different package, it's not in the main package. The asterisk says it's a pointer, that means I may return nil as well. Remember the values here don't accept nulls that here in Go are nills unless it's a pointer, if it's a pointer, then asterisk means I can send nills as well.

[00:07:57]
So then I can call my logger.Newlogger, I receives the file path so we can call this movie service the log or movie log, movie log, movie output log, however you wanna call this, it's just a file name. And of course, this is relative to the execution of our server, you can use also an absolute path.

[00:08:23]
Don't put this in the public folder, because if you put that file in the public folder, it will be available for every user, okay, so don't do that. It should be outside of the public folder, that log file. This idea is that new logger is following the pattern we see here, of error management in Go.

[00:08:49]
So if for some reason you cannot open the file, why, maybe I don't have permissions in the file system to open the file or whatever. There are no more space in the disk, anything can happen. I'm returning two values, so that's the design pattern in Go. So functions that may trigger an error, we don't have exceptions here, we don't have try catch.

[00:09:12]
We are just returning two values, okay? The possible value, and that's why it has an asterisk, it's a pointer, because maybe it's not there, and then the error. So if there are no errors, I'm returning the object and nil as an error. And if there are errors, I'm returning nil as the object and then the error, okay, makes sense.

[00:09:39]
This is, again, this is a goal design pattern that you may already know in case you are coming from node.js or javascript, this is similar node.js and how you work. Also, when you open the file system before promises, where the callbacks also have an error, but in the reverse order, kind of the same pattern.

[00:10:01]
So that means that we should save.
>> Maximiliano Firtman: Both values here,
>> Maximiliano Firtman: Remember that we can return more than one value in Go functions, and we are going to check if we do have an error. Well now we need to log to the File c through the operating system, we don't have any other initialice logger.

[00:10:33]
>> Maximiliano Firtman: Of course if we cannot create the log, the only thing we have is to send a message to the operating system, a fatal error, okay?
>> Maximiliano Firtman: And then, we will return the LogInstance, and we're going to use defer to close.
>> Maximiliano Firtman: That LogInstance, we'll defer that to the end, so we close it at the end.

[00:11:02]
But we set that close now, that's the idea of deferring Go. And now of course, Go is always complaining that I'm not using that instance. Remember Go is not letting you create variables that you are not using. So it won't compile, that's why it's complaining, but yeah, we will use that at some point.

[00:11:26]
So the idea is that, for example, if the server is failing, we can now use our LogInstance, and try to log in this case an error saying, Server failed. So by the way, it also needs the error that we passed an argument. It's not just sending a message to the output, it's also saving that information in a file.

[00:12:01]
So from now on, every time we want to log messages to the console, we're going to do that with our logger, not with format print or with print, okay, so this is much better than format print. We typically in production, we don't use format print to send messages, we use a logger.

[00:12:25]
Then if you want that logger to send messages to the console, okay, it's up to you. But the idea is that later you can change that with the server side login system or whatever. Now if I save this, again, I've just saved this, the problem that I still have is if my server is running, it's not taking that new part because I need to install air.

[00:12:54]
By the way, if you are used to Nodemon, you can also use Nodemon as well. You need to pass some arguments to tell them that you're not expecting child script files but go files. But Nodemon can also be useful in this case. But to use Nodemon, you also need to have NPM and Node.js installing your system.

[00:13:12]
So it's completely separated from Go, okay? Anyway, do you have any question at this point?
>> Speaker 2: Can you explain the import path for this logger that we imported, front end masters.com reeling logger cuz I'm just confused cuz that's not where it is locally for the file that we created.

[00:13:33]
>> Maximiliano Firtman: Okay, let's talk about that, so the question is about importing other packages. So actually, in Go, we have modules, let's say your project, and then inside the module, you have packages. What's a package, files in a folder that they start with the package keyword at the top with the name of the package.

[00:13:55]
So every file in the folder logger that have package logger are part of the same package. When you are in main.go, you're in the main package, not in the logger package. So even if it's part of your module, you have to import your files and importing your files needs kind of an absolute URL and it's the name of your module.

[00:14:25]
And where this is coming from, it's coming here from go.mod. So it's the name of your module, forward slash, the name of the package you're importing from that module, okay? The other imports that we have here are actually system packages from go, like they are part of the standard library, so that's why they don't need that full path, okay, does it make sense?

[00:14:51]
>> Speaker 2: Thank you.
>> Maximiliano Firtman: So later, we will start using other modules as well, like community based modules. In that case, we will be importing from other modules as well, remember that it looks like a URL, that's kind of a pattern in Go, but it's not mandatory. And of course, no one is validating that that URL actually exists.

[00:15:14]
Typically, is the name of your company, or sometimes you use GitHub URL, so github.com/ like a real URL or sometimes it's a real one, sometimes it's not, that's the name of your module. And remember that in Go, when you are importing a package, you are importing everything that the package has exported.

[00:15:36]
Does anyone remember how do you export things in Go?
>> Speaker 3: Capital letter.
>> Maximiliano Firtman: Capital letter, so everything that in the package starts with a capital letter, such as logger here or new logger, is actually exported. So if I create another function that is with lowercase letter is not exported and only the same package can use it.

[00:16:05]
That applies to variables, constants, functions, structures, okay, just as an overview of Go. Okay, cool, well, now that we have a logger, we can start building the rest of the parts in our back end, okay? We did that again beforehand, so we are ready to send messages to that logger, and we will use it because at one point we will get errors, okay, and we will use that logger to actually find the error.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now