Skip to content

Commit b42c1e1

Browse files
committed
rename code directory
1 parent 274469c commit b42c1e1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+583
-639
lines changed

chapters/ch04-logtar-our-logging-library.md

Lines changed: 178 additions & 188 deletions
Large diffs are not rendered by default.

chapters/ch04.1-refactoring-the-code.md

Lines changed: 300 additions & 306 deletions
Large diffs are not rendered by default.

chapters/ch04.2-writing-logs.md

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Writing logs
44

5-
> The code for the entire chapter can be found [at the code/chapter_04.2 directory](/code/chapter_04.2/)
5+
> The code for the entire chapter can be found [at the src/chapter_04.2 directory](/src/chapter_04.2/)
66
77
We've covered how to build the core utility helpers that will help us construct our logging library in a more modular way. However, we haven't gotten to the fun part of actually writing logs yet.
88

@@ -30,23 +30,23 @@ When logging is performed synchronously, each log entry is written immediately t
3030
3131
By decoupling the logging process from the main application logic, we can achieve several advantages:
3232

33-
- **Improved Performance:** Asynchronous logging allows the main application thread to continue executing without waiting for log writes to complete. This can be crucial for applications that require high responsiveness and throughput.
33+
- **Improved Performance:** Asynchronous logging allows the main application thread to continue executing without waiting for log writes to complete. This can be crucial for applications that require high responsiveness and throughput.
3434

35-
- **Reduced I/O Overhead:** Writing log messages to disk can be an I/O-intensive operation. By batching multiple log messages together and writing them in one go, you reduce the frequency of disk I/O operations, which can improve efficiency.
35+
- **Reduced I/O Overhead:** Writing log messages to disk can be an I/O-intensive operation. By batching multiple log messages together and writing them in one go, you reduce the frequency of disk I/O operations, which can improve efficiency.
3636

37-
- **Better Resource Utilization:** Asynchronous logging allows you to optimize resource utilization, such as managing concurrent log writes, handling errors without disrupting the main flow, and efficiently managing file handles.
37+
- **Better Resource Utilization:** Asynchronous logging allows you to optimize resource utilization, such as managing concurrent log writes, handling errors without disrupting the main flow, and efficiently managing file handles.
3838

39-
- **Enhanced Scalability:** Applications with multiple threads or processes benefit from asynchronous logging because it minimizes contention for resources like the log file. This is particularly valuable in scenarios where multiple components are concurrently generating log messages
39+
- **Enhanced Scalability:** Applications with multiple threads or processes benefit from asynchronous logging because it minimizes contention for resources like the log file. This is particularly valuable in scenarios where multiple components are concurrently generating log messages
4040

4141
### 4. Getting Caller Information (Module and Line Number)
4242

4343
Including caller information, such as the file name and line number from which a log message originated, can significantly enhance the effectiveness of our logging library. This feature provides contextual insight into where specific events occurred in the codebase, making it easier to identify the source of issues and troubleshoot them.
4444

4545
When an application encounters an error or unexpected behavior, having access to the module and line number associated with the log message allows developers to:
4646

47-
- Quickly locate the exact location in the code where the event occurred.
48-
- Understand the sequence of events leading up to the issue.
49-
- Make precise code adjustments to fix problems.
47+
- Quickly locate the exact location in the code where the event occurred.
48+
- Understand the sequence of events leading up to the issue.
49+
- Make precise code adjustments to fix problems.
5050

5151
Implementing this feature might involve using techniques from the programming language's stack trace or introspection mechanisms. Here's a high-level overview of how you could achieve this:
5252

@@ -229,9 +229,9 @@ The "Don't Repeat Yourself" (DRY) principle is a basic concept in software devel
229229

230230
DRY encourages developers to write clean, efficient, and modular code by:
231231

232-
- Reducing the chances of errors: Duplicated code increases the chances of mistakes or bugs when changes are made in one place but not in others.
233-
- Simplifying maintenance: When a change is required, you only need to update the code in one place, making it easier to keep your codebase up-to-date and consistent.
234-
- Enhancing readability: Code that is free from unnecessary duplication is easier to understand and follow, making it more accessible to other developers.
232+
- Reducing the chances of errors: Duplicated code increases the chances of mistakes or bugs when changes are made in one place but not in others.
233+
- Simplifying maintenance: When a change is required, you only need to update the code in one place, making it easier to keep your codebase up-to-date and consistent.
234+
- Enhancing readability: Code that is free from unnecessary duplication is easier to understand and follow, making it more accessible to other developers.
235235

236236
Although following the DRY principle is generally beneficial, there can be situations where duplication might not necessarily be a bad thing. Not every instance of code repetition needs to be eliminated, and striving for absolute **DRY**ness in all cases might lead to overcomplicated solutions or premature abstraction.
237237

@@ -428,37 +428,37 @@ There's a lot going on in this method. Let's break it down.
428428

429429
4. `.replace(/[\.:]+/g, "-")` is a regular expression operation. Let's break down the regex:
430430

431-
- the square brackets [] are used to define a character class. A character class is a way to specify a set of characters from which a single character can match. For example:
431+
- the square brackets [] are used to define a character class. A character class is a way to specify a set of characters from which a single character can match. For example:
432432

433-
- [abc] matches any single character that is either 'a', 'b', or 'c'.
434-
- [0-9] matches any single digit from 0 to 9.
435-
- [a-zA-Z] matches any single alphabetical character, regardless of case.
433+
- [abc] matches any single character that is either 'a', 'b', or 'c'.
434+
- [0-9] matches any single digit from 0 to 9.
435+
- [a-zA-Z] matches any single alphabetical character, regardless of case.
436436

437-
You can also use special characters within character classes to match certain character types, like `\d` for digits, `\w` for word characters, `\s` for whitespace, etc.
437+
You can also use special characters within character classes to match certain character types, like `\d` for digits, `\w` for word characters, `\s` for whitespace, etc.
438438

439-
In this case we are looking for all the dot (`.`) characters and colon (`:`) characters in the string.
439+
In this case we are looking for all the dot (`.`) characters and colon (`:`) characters in the string.
440440

441-
- `\.` matches a literal dot character. Since the dot (`.`) is a special character in regular expression, known as a wildcard. It matches any single character except for a newline character (`\n`). This is useful when you want to match any character, which is often used in pattern matching.
441+
- `\.` matches a literal dot character. Since the dot (`.`) is a special character in regular expression, known as a wildcard. It matches any single character except for a newline character (`\n`). This is useful when you want to match any character, which is often used in pattern matching.
442442

443-
However, in this case, we want to match a literal dot character in the string (the dot in the date-time format "00.000Z"). To achieve this, we need to escape the dot character by preceding it with a backslash (`\`). When you place a backslash before a special character, it indicates that you want to match the literal character itself, rather than its special meaning.
443+
However, in this case, we want to match a literal dot character in the string (the dot in the date-time format "00.000Z"). To achieve this, we need to escape the dot character by preceding it with a backslash (`\`). When you place a backslash before a special character, it indicates that you want to match the literal character itself, rather than its special meaning.
444444

445-
- `+` matches one or more of any character except newline. We match for all the characters following the dot (.) and the (:) character.
445+
- `+` matches one or more of any character except newline. We match for all the characters following the dot (.) and the (:) character.
446446

447-
- `/g` is the global flag, indicating that the replacement should be applied to all occurrences of the pattern.
447+
- `/g` is the global flag, indicating that the replacement should be applied to all occurrences of the pattern.
448448

449-
- So, the regex `[\.:]+` matches the dot or colon and all the repeated occurences of these 2 characters.
449+
- So, the regex `[\.:]+` matches the dot or colon and all the repeated occurences of these 2 characters.
450450

451-
- The replacement `"-"` removes the dot and all characters after it and replaces it with a hyphen (`-`).
451+
- The replacement `"-"` removes the dot and all characters after it and replaces it with a hyphen (`-`).
452452

453453
5. The result of the `replace` operation is a modified version of the ISO string, which now includes only the date and time portion, without the fractional seconds.
454454

455455
6. `.log` is appended to the modified date and time string to form the final log file name.
456456

457457
7. `await fs.open(file_name, "a+")` opens or creates the log file using the `fs.open` function with "a+" flag. We talked about the modes in a [previous chapter](https://github.com/ishtms/learn-nodejs-hard-way/blob/master/chapters/ch03-working-with-files.md#flag-argument)
458458

459-
- If the file doesn't exist, it will be created.
460-
- If the file exists, data can be appended to it.
461-
- The `"a+"` mode allows both reading and appending. Appending means, we begin writing to the end of the file instead of from the 1st line. However, if the file is empty, it starts from the beginning.
459+
- If the file doesn't exist, it will be created.
460+
- If the file exists, data can be appended to it.
461+
- The `"a+"` mode allows both reading and appending. Appending means, we begin writing to the end of the file instead of from the 1st line. However, if the file is empty, it starts from the beginning.
462462

463463
This code initializes the logger by creating or opening a log file with a name based on the current date. The regular expression is used to remove the fractional seconds from the ISO date string, and the resulting string is used as part of the log file name. This allows for creating a new log file every time the `init` method is called, typically representing logs for a specific time period.
464464

@@ -516,9 +516,9 @@ How do we fix it? Simply by `await`ing the `init()` method.
516516
const { Logger, LogConfig } = require("./index");
517517

518518
async function main() {
519-
const logger = Logger.with_config(LogConfig.from_file("./config.json"));
520-
await logger.init();
521-
console.log("End of the file");
519+
const logger = Logger.with_config(LogConfig.from_file("./config.json"));
520+
await logger.init();
521+
console.log("End of the file");
522522
}
523523

524524
main();
@@ -559,9 +559,9 @@ const path = require("node:path");
559559
const { Logger, LogConfig } = require("./index");
560560

561561
async function main() {
562-
const logger = Logger.with_config(LogConfig.from_file(path.join(__dirname, "config.json")));
563-
await logger.init();
564-
console.log("End of the file");
562+
const logger = Logger.with_config(LogConfig.from_file(path.join(__dirname, "config.json")));
563+
await logger.init();
564+
console.log("End of the file");
565565
}
566566

567567
main();
@@ -641,15 +641,15 @@ But, require is not just a function!
641641

642642
For example:
643643

644-
- `require.resolve('module-name')`: Returns the path of the module without actually loading it.
645-
- `require.cache`: Provides access to the cache of loaded modules.
646-
- `require.main`: Provides access to the `Module` object representing the entry script loaded when the Node.js process launched. This is exactly what we need.
644+
- `require.resolve('module-name')`: Returns the path of the module without actually loading it.
645+
- `require.cache`: Provides access to the cache of loaded modules.
646+
- `require.main`: Provides access to the `Module` object representing the entry script loaded when the Node.js process launched. This is exactly what we need.
647647

648648
The reason `require` might feel like both an object and a function is because JavaScript allows functions to have properties. You can test this yourself
649649

650650
```js
651651
function my_fun() {
652-
console.log("hi");
652+
console.log("hi");
653653
}
654654
my_fun.hey = "there";
655655

@@ -671,26 +671,26 @@ const path = require("path");
671671
* @returns {fs_sync.PathLike} The path to the directory.
672672
*/
673673
function check_and_create_dir(path_to_dir) {
674-
const log_dir = path.resolve(require.main.path, path_to_dir);
675-
if (!fs_sync.existsSync(log_dir)) {
676-
fs_sync.mkdirSync(log_dir, { recursive: true });
677-
}
674+
const log_dir = path.resolve(require.main.path, path_to_dir);
675+
if (!fs_sync.existsSync(log_dir)) {
676+
fs_sync.mkdirSync(log_dir, { recursive: true });
677+
}
678678

679-
return log_dir;
679+
return log_dir;
680680
}
681681

682682
module.exports = {
683-
check_and_create_dir,
683+
check_and_create_dir,
684684
};
685685
```
686686

687687
Let's go through the `check_and_create_dir` function's code line by line.
688688

689689
1. The `path.resolve()` function creates an absolute path by combining a sequence of paths or path segments.
690690

691-
It processes the sequence from right to left, with each subsequent path added to the beginning until an absolute path is created. For example, if the path segments are `/foo`, `/bar`, and `baz`, calling `path.resolve('/foo', '/bar', 'baz')` would return `/bar/baz` because `'/bar' + '/' + 'baz'` creates an absolute path, but `'baz'` does not.
691+
It processes the sequence from right to left, with each subsequent path added to the beginning until an absolute path is created. For example, if the path segments are `/foo`, `/bar`, and `baz`, calling `path.resolve('/foo', '/bar', 'baz')` would return `/bar/baz` because `'/bar' + '/' + 'baz'` creates an absolute path, but `'baz'` does not.
692692

693-
If, after processing all the segments in the given path, an absolute path hasn't been created yet, then the current working directory is used instead.
693+
If, after processing all the segments in the given path, an absolute path hasn't been created yet, then the current working directory is used instead.
694694

695695
2. The `require.main.path` holds the absolute path to the directory of the entry point. The entry point is the `test.js` in our case. Or whatever file you specify while running `node file_name.js` command.
696696

@@ -767,14 +767,14 @@ const path = require("node:path");
767767
const { Logger, LogConfig } = require("./index");
768768

769769
async function initialize_logger() {
770-
let logger = Logger.with_config(LogConfig.from_file(path.join(__dirname, "config.json")));
771-
await logger.init();
770+
let logger = Logger.with_config(LogConfig.from_file(path.join(__dirname, "config.json")));
771+
await logger.init();
772772

773-
return logger;
773+
return logger;
774774
}
775775
async function main() {
776-
let logger = await initialize_logger();
777-
logger.error("This is an error message");
776+
let logger = await initialize_logger();
777+
logger.error("This is an error message");
778778
}
779779

780780
main();
@@ -800,6 +800,6 @@ Perfect! Everything seems to be working now. The logs are being saved, and we ca
800800

801801
We'll take care of all this in the next chapter.
802802

803-
> The code for the entire chapter can be found [at the code/chapter_04.2 directory](/code/chapter_04.2/)
803+
> The code for the entire chapter can be found [at the src/chapter_04.2 directory](/src/chapter_04.2/)
804804
805805
[![Read Next](/assets/imgs/next.png)](/chapters/ch04.3-capturing-metadata.md)

0 commit comments

Comments
 (0)