Skip to content

Commit 175fda0

Browse files
committed
add code for the chapter 04.5
1 parent a5ae5ef commit 175fda0

23 files changed

+1442
-0
lines changed

code/chapter_04.5/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/*/**
2+
test.js
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"deno.enable": true,
3+
"deno.lint": true,
4+
"deno.unstable": true
5+
}

code/chapter_04.5/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# A fast, flexible and configurable Logging framework for NodeJS
2+
3+
Master the art of backend development and servers with the free open source book on [github](https://github.com/ishtms/learn-nodejs-hard-way)
4+
5+
> Note: This should not be used in production yet. This is not a complete project.
6+
![](https://uddrapi.com/api/img?page=logtar%20homepage)

code/chapter_04.5/config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"level": 0,
3+
"log_prefix": "LogTar_",
4+
"rolling_config": {
5+
"size_threshold": 10240,
6+
"time_threshold": 60
7+
}
8+
}

code/chapter_04.5/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib/logtar')
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
const fs = require("node:fs");
2+
3+
const { LogLevel } = require("../utils/log-level");
4+
const { RollingConfig } = require("./rolling-config");
5+
6+
class LogConfig {
7+
/**
8+
* @type {LogLevel}
9+
* @private
10+
* @description The log level to be used.
11+
*/
12+
#level = LogLevel.Info;
13+
14+
/**
15+
* @type {RollingConfig}
16+
* @private
17+
*/
18+
#rolling_config;
19+
20+
/**
21+
* @type {string}
22+
* @private
23+
* @description The prefix to be used for the log file name.
24+
*
25+
* If the file prefix is `MyFilePrefix_` the log files created will have the name
26+
* `MyFilePrefix_2021-09-01.log`, `MyFilePrefix_2021-09-02.log` and so on.
27+
*/
28+
#file_prefix = "Logtar_";
29+
30+
constructor() {
31+
this.#rolling_config = RollingConfig.with_defaults();
32+
}
33+
34+
/**
35+
* @returns {LogConfig} A new instance of LogConfig with default values.
36+
*/
37+
static with_defaults() {
38+
return new LogConfig();
39+
}
40+
41+
/**
42+
* @param {string} file_path The path to the config file.
43+
* @returns {LogConfig} A new instance of LogConfig with values from the config file.
44+
* @throws {Error} If the file_path is not a string.
45+
*/
46+
static from_file(file_path) {
47+
const file_contents = fs.readFileSync(file_path);
48+
return LogConfig.from_json(JSON.parse(file_contents));
49+
}
50+
51+
/**
52+
* @param {Object} json The json object to be parsed into {LogConfig}.
53+
* @returns {LogConfig} A new instance of LogConfig with values from the json object.
54+
*/
55+
static from_json(json) {
56+
let log_config = new LogConfig();
57+
Object.keys(json).forEach((key) => {
58+
switch (key) {
59+
case "level":
60+
log_config = log_config.with_log_level(json[key]);
61+
break;
62+
case "rolling_config":
63+
log_config = log_config.with_rolling_config(json[key]);
64+
break;
65+
case "file_prefix":
66+
log_config = log_config.with_file_prefix(json[key]);
67+
break;
68+
}
69+
});
70+
return log_config;
71+
}
72+
73+
/**
74+
* @param {LogConfig} log_config The log config to be validated.
75+
* @throws {Error} If the log_config is not an instance of LogConfig.
76+
*/
77+
static assert(log_config) {
78+
if (arguments.length > 0 && !(log_config instanceof LogConfig)) {
79+
throw new Error(
80+
`log_config must be an instance of LogConfig. Unsupported param ${JSON.stringify(log_config)}`
81+
);
82+
}
83+
}
84+
85+
/**
86+
* @returns {LogLevel} The current log level.
87+
*/
88+
get level() {
89+
return this.#level;
90+
}
91+
92+
/**
93+
* @param {LogLevel} log_level The log level to be set.
94+
* @returns {LogConfig} The current instance of LogConfig.
95+
* @throws {Error} If the log_level is not an instance of LogLevel.
96+
*/
97+
with_log_level(log_level) {
98+
LogLevel.assert(log_level);
99+
this.#level = log_level;
100+
return this;
101+
}
102+
103+
/**
104+
* @returns {RollingConfig} The current rolling config.
105+
*/
106+
get rolling_config() {
107+
return this.#rolling_config;
108+
}
109+
110+
/**
111+
* @param {RollingConfig} config The rolling config to be set.
112+
* @returns {LogConfig} The current instance of LogConfig.
113+
* @throws {Error} If the config is not an instance of RollingConfig.
114+
*/
115+
with_rolling_config(config) {
116+
this.#rolling_config = RollingConfig.from_json(config);
117+
return this;
118+
}
119+
120+
/**
121+
* @returns {String} The current max file size.
122+
*/
123+
get file_prefix() {
124+
return this.#file_prefix;
125+
}
126+
127+
/**
128+
* @param {string} file_prefix The file prefix to be set.
129+
* @returns {LogConfig} The current instance of LogConfig.
130+
* @throws {Error} If the file_prefix is not a string.
131+
*/
132+
with_file_prefix(file_prefix) {
133+
if (typeof file_prefix !== "string") {
134+
throw new Error(`file_prefix must be a string. Unsupported param ${JSON.stringify(file_prefix)}`);
135+
}
136+
137+
this.#file_prefix = file_prefix;
138+
return this;
139+
}
140+
}
141+
142+
module.exports = { LogConfig };
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
const { RollingTimeOptions, RollingSizeOptions } = require("../utils/rolling-options");
2+
3+
class RollingConfig {
4+
/**
5+
* Roll/Create new file every time the current file size exceeds this threshold in `seconds`.
6+
*
7+
* @type {RollingTimeOptions}
8+
* @private
9+
*
10+
*/
11+
#time_threshold = RollingTimeOptions.Hourly;
12+
13+
/**
14+
* @type {RollingSizeOptions}
15+
* @private
16+
*/
17+
#size_threshold = RollingSizeOptions.FiveMB;
18+
19+
/**
20+
* @returns {RollingConfig} A new instance of RollingConfig with default values.
21+
*/
22+
static with_defaults() {
23+
return new RollingConfig();
24+
}
25+
26+
/**
27+
* @param {number} size_threshold Roll/Create new file every time the current file size exceeds this threshold.
28+
* @returns {RollingConfig} The current instance of RollingConfig.
29+
*/
30+
with_size_threshold(size_threshold) {
31+
RollingSizeOptions.assert(size_threshold);
32+
this.#size_threshold = size_threshold;
33+
return this;
34+
}
35+
36+
/**
37+
* @param {time_threshold} time_threshold Roll/Create new file every time the current file size exceeds this threshold.
38+
* @returns {RollingConfig} The current instance of RollingConfig.
39+
* @throws {Error} If the time_threshold is not an instance of RollingTimeOptions.
40+
*/
41+
with_time_threshold(time_threshold) {
42+
RollingTimeOptions.assert(time_threshold);
43+
this.#time_threshold = time_threshold;
44+
return this;
45+
}
46+
47+
/**
48+
* @param {Object} json The json object to be parsed into {RollingConfig}.
49+
* @returns {RollingConfig} A new instance of RollingConfig with values from the json object.
50+
* @throws {Error} If the json is not an object.
51+
*/
52+
static from_json(json) {
53+
let rolling_config = new RollingConfig();
54+
55+
Object.keys(json).forEach((key) => {
56+
switch (key) {
57+
case "size_threshold":
58+
rolling_config = rolling_config.with_size_threshold(json[key]);
59+
break;
60+
case "time_threshold":
61+
rolling_config = rolling_config.with_time_threshold(json[key]);
62+
break;
63+
}
64+
});
65+
66+
return rolling_config;
67+
}
68+
69+
/**
70+
* @returns {RollingTimeOptions} The current time threshold.
71+
*/
72+
get time_threshold() {
73+
return this.#time_threshold;
74+
}
75+
76+
/**
77+
* @returns {RollingSizeOptions} The current size threshold.
78+
*/
79+
get size_threshold() {
80+
return this.#size_threshold;
81+
}
82+
}
83+
84+
module.exports = { RollingConfig };

0 commit comments

Comments
 (0)