@stonyx/logs 1.0.1-alpha.7 → 1.0.1-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,10 +31,10 @@
31
31
 
32
32
  ---
33
33
 
34
- **Chronicle** is built on top of all the great work done by "Sindre Sorhus" and other collaborators of the [chalk](https://www.npmjs.com/package/chalk) project.
35
- This project is not directly associated with chalk other than chalk being a core dependency of **Chronicle**.
34
+ **Log** is built on top of all the great work done by "Sindre Sorhus" and other collaborators of the [chalk](https://www.npmjs.com/package/chalk) project.
35
+ This project is not directly associated with chalk other than chalk being a core dependency of **Log**.
36
36
 
37
- **IMPORTANT**: Please note that although **Chronicle** can be configured to any color through chalk, your output is subject to your terminal's color limitations.
37
+ **IMPORTANT**: Please note that although **Log** can be configured to any color through chalk, your output is subject to your terminal's color limitations.
38
38
 
39
39
  ## Highlights
40
40
 
@@ -45,27 +45,27 @@ This project is not directly associated with chalk other than chalk being a core
45
45
  ## Install
46
46
 
47
47
  ```sh
48
- npm install node-chronicle
48
+ npm install @stonyx/logs
49
49
  ```
50
50
 
51
51
  ## Usage
52
52
 
53
53
  ```js
54
- import Chronicle from 'node-chronicle';
54
+ import Log from '@stonyx/logs';
55
55
 
56
- const chronicle = new Chronicle();
56
+ const log = new Log();
57
57
 
58
- chronicle.info('Info: sample application has started');
59
- chronicle.warn('Warning: this is just a sample');
60
- chronicle.error('Error: no application logic detected', true); // logs to logs/error.log file
58
+ log.info('Info: sample application has started');
59
+ log.warn('Warning: this is just a sample');
60
+ log.error('Error: no application logic detected', true); // logs to logs/error.log file
61
61
  ```
62
62
 
63
63
  Easily define your own logging mechanism and color-coding preference:
64
64
 
65
65
  ```js
66
- import Chronicle from 'node-chronicle';
66
+ import Log from '@stonyx/logs';
67
67
 
68
- const chronicle = new Chronicle({
68
+ const log = new Log({
69
69
  systemLogs: {
70
70
  blue: '#007cae', // indigo blue
71
71
  yellow: '#ae8f00', // bright orange
@@ -73,17 +73,17 @@ const chronicle = new Chronicle({
73
73
  },
74
74
  });
75
75
 
76
- chronicle.blue('Info: using custom method blue, sample application has started');
77
- chronicle.yellow('Warning: using custom method yellow, this is just a sample');
78
- chronicle.red('Error: using custom method red, no application logic detected', false);
76
+ log.blue('Info: using custom method blue, sample application has started');
77
+ log.yellow('Warning: using custom method yellow, this is just a sample');
78
+ log.red('Error: using custom method red, no application logic detected', false);
79
79
  ```
80
80
 
81
81
  Customize logging options to best suit your project
82
82
 
83
83
  ```js
84
- import Chronicle from 'node-chronicle';
84
+ import Log from '@stonyx/logs';
85
85
 
86
- const chronicle = new Chronicle({
86
+ const log = new Log({
87
87
  logToFileByDefault: true,
88
88
  logTimestamp: true,
89
89
  path: 'custom-logs', // <project root>/custom-logs/*.log
@@ -91,7 +91,7 @@ const chronicle = new Chronicle({
91
91
  suffix: '\n=============================================================== \n',
92
92
  });
93
93
 
94
- chronicle.info('Info: sample application has started');
94
+ log.info('Info: sample application has started');
95
95
  ```
96
96
  ![](https://github.com/abofs/stonyx-logs/raw/main/media/examples/custom-options.jpg)
97
97
 
@@ -99,15 +99,15 @@ chronicle.info('Info: sample application has started');
99
99
  Add additional log types extending the default options of "info", "warn", "error" and "debug"
100
100
 
101
101
  ```js
102
- import Chronicle from '../source/index.js';
102
+ import Log from '@stonyx/logs';
103
103
 
104
- const chronicle = new Chronicle({ additionalLogs: { question: 'green' } });
104
+ const log = new Log({ additionalLogs: { question: 'green' } });
105
105
 
106
106
  // create additional log with direct chalk configuration
107
- chronicle.defineType('query', chronicle.chalk().black.bgGreen);
107
+ log.defineType('query', log.chalk().black.bgGreen);
108
108
 
109
- chronicle.question('What will a fully custom chalk color function look like?');
110
- await chronicle.query('This is what a custom chalk color setting looks like', true);
109
+ log.question('What will a fully custom chalk color function look like?');
110
+ await log.query('This is what a custom chalk color setting looks like', true);
111
111
  ```
112
112
  ![](https://github.com/abofs/stonyx-logs/raw/main/media/examples/additional-logs.jpg)
113
113
 
@@ -115,7 +115,7 @@ await chronicle.query('This is what a custom chalk color setting looks like', tr
115
115
 
116
116
  ### Defining Logs & Colors
117
117
 
118
- By default, **Chronicle** is instantiated with the following options:
118
+ By default, **Log** is instantiated with the following options:
119
119
 
120
120
  ```js
121
121
  additionalLogs: {},
@@ -126,10 +126,10 @@ By default, **Chronicle** is instantiated with the following options:
126
126
  },
127
127
  ```
128
128
 
129
- You can add to a new log/color setting by passing the `additionalLogs` option to the **Chronicle** constructor. Any setting that already exists in `systemLogs` will be replaced, otherwise they will be added.
129
+ You can add to a new log/color setting by passing the `additionalLogs` option to the **Log** constructor. Any setting that already exists in `systemLogs` will be replaced, otherwise they will be added.
130
130
 
131
131
  ```js
132
- const chronicle = new Chronicle({ additionalLogs: { info: 'green', custom: 'cyan' } });
132
+ const log = new Log({ additionalLogs: { info: 'green', custom: 'cyan' } });
133
133
 
134
134
  // output configuration:
135
135
  {
@@ -140,13 +140,13 @@ You can add to a new log/color setting by passing the `additionalLogs` option to
140
140
  }
141
141
  ```
142
142
 
143
- **Chronicle** will generate convenience methods for all keys provided, with the corresponding color settings. The example above would create the following convenience methods, for logging:
143
+ **Log** will generate convenience methods for all keys provided, with the corresponding color settings. The example above would create the following convenience methods, for logging:
144
144
 
145
145
  ```js
146
- chronicle.info() // green output
147
- chronicle.warn() // yellow output
148
- chronicle.error() // red output
149
- chronicle.custom() // cyan output
146
+ log.info() // green output
147
+ log.warn() // yellow output
148
+ log.error() // red output
149
+ log.custom() // cyan output
150
150
  ```
151
151
 
152
152
  These methods can then be called in your application with [logging parameters](#logging-parameters).
@@ -157,7 +157,7 @@ Additionally, these methods return a promise when `logToFile` is true, allowing
157
157
 
158
158
  ```js
159
159
  async method() {
160
- await chronicle.error('error message', true);
160
+ await log.error('error message', true);
161
161
 
162
162
  // do something after logs/error.log (default) is created
163
163
  }
@@ -165,7 +165,7 @@ async method() {
165
165
 
166
166
  ### The Debug Method
167
167
 
168
- **Chronicle** allows for the `chronicle.debug()` method to be overridden by a color setting. However, by default we do not define a color for debug and debug is handled differently. For console logging, all **debug** does is output the following:
168
+ **Log** allows for the `log.debug()` method to be overridden by a color setting. However, by default we do not define a color for debug and debug is handled differently. For console logging, all **debug** does is output the following:
169
169
 
170
170
  ```js
171
171
  // For logging to console:
@@ -175,12 +175,12 @@ console.dir(content);
175
175
  JSON.stringify(content, null, 2);
176
176
  ```
177
177
 
178
- We believe that when wanting to output complicated objects or debug **typescript** applications, there are better methods than utilizing this **Chronicle** package. But for anyone who's fully incorporated **Chronicle** into their project, this function offers some convenience.
178
+ We believe that when wanting to output complicated objects or debug **typescript** applications, there are better methods than utilizing this **Log** package. But for anyone who's fully incorporated **Log** into their project, this function offers some convenience.
179
179
 
180
180
  ### Logging Parameters
181
181
 
182
182
  ```js
183
- chronicle.error('error message', true, false); // content, logToFile, overwrite
183
+ log.error('error message', true, false); // content, logToFile, overwrite
184
184
  ```
185
185
 
186
186
  | Parameter | Type | Default | Description |
@@ -192,15 +192,16 @@ chronicle.error('error message', true, false); // content, logToFile, overwrite
192
192
  **logToFile** will log to *<project-root>/logs* unless [configured](#configuration) differently during instantiation. <br>
193
193
  ### Configuration
194
194
 
195
- When instantiating **Chronicle**, you can pass an object to customize your settings. Below is the default configuration:
195
+ When instantiating **Log**, you can pass an object to customize your settings. Below is the default configuration:
196
196
 
197
197
  ```js
198
- const chronicle = new Chronicle({
198
+ const log = new Log({
199
199
  logToFileByDefault: false,
200
200
  logTimestamp: false,
201
201
  path: 'logs/',
202
202
  prefix: '',
203
203
  suffix: '',
204
+ filename: '',
204
205
  additionalLogs: {},
205
206
  systemLogs: {
206
207
  info: 'cyan',
@@ -217,27 +218,28 @@ const chronicle = new Chronicle({
217
218
  | `path` | **String** | *'logs/'* | Path in which to store log files. This setting is relative to your project's root directory. |
218
219
  | `prefix` | **String** | *''* | Prefix string to prepend all log messages for all log types with the exception of *debug*. |
219
220
  | `suffix` | **String** | *''* | Suffix string to tack on to all log messages for all log types with the exception of *debug*. |
221
+ | `filename` | **String** | *''* | Template for log file names with variable support. Defaults to `{type}.log` when empty. See [dynamic file names](#dynamic-file-names). |
220
222
  | `additionalLogs` | **Object** | | Key value pair object containing log type to color setting for logs that will be merged with `systemLogs` |
221
- | `systemLogs` | **Object** | | Key value pair object containing log type to color setting for main **Chronicle** logs available in application |
223
+ | `systemLogs` | **Object** | | Key value pair object containing log type to color setting for main **Log** logs available in application |
222
224
 
223
225
  `additionalLogs` and `systemLogs` are explained with more detail in the [defining logs and colors](#defining-logs) section.
224
226
 
225
227
  ### Advanced Configuration
226
228
 
227
- You may want to do more than just pick a basic color for your output. **chalk** offers a variety of different options, and can be configured via `defineType()`. **Chronicle** exposes the chalk instance via `chalk()` so that you don't have to import **chalk** directly into your project. Here is an example of how you can use this method to fully customize your log color setting:
229
+ You may want to do more than just pick a basic color for your output. **chalk** offers a variety of different options, and can be configured via `defineType()`. **Log** exposes the chalk instance via `chalk()` so that you don't have to import **chalk** directly into your project. Here is an example of how you can use this method to fully customize your log color setting:
228
230
 
229
231
  ```js
230
- const chronicle = new Chronicle();
232
+ const log = new Log();
231
233
 
232
- chronicle.defineType('critical', chronicle.chalk().bold.red);
233
- chronicle.critical('This is a critical error');
234
+ log.defineType('critical', log.chalk().bold.red);
235
+ log.critical('This is a critical error');
234
236
  ```
235
237
 
236
238
  Additionally, any [configuration](#configuration) that can be set during instantiation, can also be applied exclusively to any given type by passing in a third **options** parameter.
237
239
 
238
240
  ```js
239
241
  // params: type, setting, options
240
- chronicle.definetype('notice', '#c0c0c0', {
242
+ log.definetype('notice', '#c0c0c0', {
241
243
  prefix: '--------------------------------------------------------------- \n',
242
244
  suffix: '\n=============================================================== \n'
243
245
  });
@@ -252,29 +254,62 @@ chronicle.definetype('notice', '#c0c0c0', {
252
254
 
253
255
 
254
256
  ```js
255
- const chronicle = new Chronicle();
257
+ const log = new Log();
256
258
 
257
- chronicle.defineType('info', chronicle.chalk().black.bgCyan);
258
- chronicle.defineType('critical', chronicle.chalk().bold.red);
259
- chronicle.defineType('dialog', 'magentaBright');
260
- chronicle.definetype('notice', '#c0c0c0', {
259
+ log.defineType('info', log.chalk().black.bgCyan);
260
+ log.defineType('critical', log.chalk().bold.red);
261
+ log.defineType('dialog', 'magentaBright');
262
+ log.definetype('notice', '#c0c0c0', {
261
263
  prefix: '--------------------------------------------------------------- \n',
262
264
  suffix: '\n=============================================================== \n'
263
265
  });
264
266
 
265
- chronicle.info('This pre-existing log now has a cyan background and black foreground');
266
- chronicle.critical('This new log is bold and red');
267
- chronicle.dialog('This new dialog is bright magenta');
268
- chronicle.notice('This new log is the hex "#c0c0c0" share of gray');
267
+ log.info('This pre-existing log now has a cyan background and black foreground');
268
+ log.critical('This new log is bold and red');
269
+ log.dialog('This new dialog is bright magenta');
270
+ log.notice('This new log is the hex "#c0c0c0" share of gray');
269
271
  ```
270
272
 
271
273
  `defineType()` can also be used as an alternative to populating the `additionalLogs` setting in the constructor, as if the setting doesn't already exist, it will then be created.
272
274
 
275
+ ### Dynamic File Names
276
+
277
+ The `filename` option supports template variables that are resolved at write-time, allowing each log type to produce uniquely named files.
278
+
279
+ #### Supported Variables
280
+
281
+ | Variable | Resolves To | Example Output |
282
+ | :---: | :--- | :--- |
283
+ | `{date}` | Current date in YYYY-MM-DD format | `2026-04-04` |
284
+ | `{type}` | Log type name | `error` |
285
+ | `{pid}` | Current process ID | `12345` |
286
+ | `{hostname}` | Machine hostname | `my-server` |
287
+
288
+ #### Examples
289
+
290
+ ```js
291
+ // Per-type filename via defineType
292
+ log.defineType('error', 'red', { filename: 'error-{date}.log' });
293
+ // writes to: logs/error-2026-04-04.log
294
+
295
+ // Per-type filename with multiple variables
296
+ log.defineType('info', 'cyan', { filename: '{type}-{hostname}-{date}.log' });
297
+ // writes to: logs/info-my-server-2026-04-04.log
298
+
299
+ // Global filename template via constructor
300
+ const log = new Log({ filename: '{type}-{date}.log' });
301
+ // all types write to: logs/<type>-2026-04-04.log
302
+ ```
303
+
304
+ When no `filename` is configured, the default behavior of `{type}.log` is preserved for full backward compatibility.
305
+
306
+ Path traversal characters (`..`, `/`, `\`) are automatically stripped from resolved file names for security.
307
+
273
308
  ## Origin
274
309
 
275
- As a team of developers who are constantly working on side projects, we often litter our codebase with TODOs to refactor convenience utils such as **chronicle** into classes of their own, or projects of their own. This usually turns into internal tech debt that never gets addressed. Furthermore, we also often find ourselves going the *copy -> paste -> modify* route of previously written useful logic, which saves us time in new projects, but not as much as it would if all we had to do was run an `npm install` instead.
310
+ As a team of developers who are constantly working on side projects, we often litter our codebase with TODOs to refactor convenience utils such as **@stonyx/logs** into classes of their own, or projects of their own. This usually turns into internal tech debt that never gets addressed. Furthermore, we also often find ourselves going the *copy -> paste -> modify* route of previously written useful logic, which saves us time in new projects, but not as much as it would if all we had to do was run an `npm install` instead.
276
311
 
277
- With that in mind, we are proud to release **chronicle** as an open source package, in hopes others will find this just as useful as we do in their own projects.
312
+ With that in mind, we are proud to release **@stonyx/logs** as an open source package, in hopes others will find this just as useful as we do in their own projects.
278
313
 
279
314
  ## Maintainers
280
315
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonyx/logs",
3
- "version": "1.0.1-alpha.7",
3
+ "version": "1.0.1-alpha.9",
4
4
  "description": "Simplified logging for node applications",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -24,7 +24,7 @@
24
24
  "log",
25
25
  "logging",
26
26
  "color-coding",
27
- "chronicle",
27
+ "stonyx",
28
28
  "history",
29
29
  "documentation",
30
30
  "document",
package/src/color.js CHANGED
@@ -22,7 +22,7 @@ export default class Color {
22
22
  // retrieves chalk color function, and fully validates output
23
23
  settingToChalkColorFunction(setting) {
24
24
  const errorMessage = 'Invalid chalk color function.'
25
- + 'For help with color settings, see https://github.com/abofs/chronicle#defining-logs--colors';
25
+ + 'For help with color settings, see https://github.com/abofs/stonyx-logs#defining-logs--colors';
26
26
 
27
27
  switch (typeof setting) {
28
28
  case 'string':
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { mkdirSync, promises as fsp } from 'fs';
2
2
  import { fileURLToPath } from 'url';
3
+ import { hostname } from 'os';
3
4
  import projectPath from 'path';
4
5
  import Color from './color.js';
5
6
 
@@ -9,6 +10,7 @@ const defaultOptions = {
9
10
  path: 'logs/', // default log directory (relative to main project root directory)
10
11
  prefix: '',
11
12
  suffix: '',
13
+ filename: '', // template for log file name (e.g. 'error-{date}.log'), defaults to '{type}.log'
12
14
 
13
15
  // log types with corresponding color settings
14
16
  additionalLogs: {},
@@ -22,7 +24,7 @@ const defaultOptions = {
22
24
  // used to sanitize defineType() options input
23
25
  const optionKeys = Object.keys(defaultOptions);
24
26
 
25
- export default class Chronicle {
27
+ export default class Log {
26
28
  constructor(options = defaultOptions) {
27
29
  options = {
28
30
  ...defaultOptions,
@@ -46,7 +48,7 @@ export default class Chronicle {
46
48
  }
47
49
  }
48
50
 
49
- // records setting and options for log type, and crates convenience method ie: chronicle.info()
51
+ // records setting and options for log type, and creates convenience method ie: log.info()
50
52
  defineType(type, setting, options = null) {
51
53
  this.color.setLogColor(type, setting);
52
54
 
@@ -59,7 +61,7 @@ export default class Chronicle {
59
61
  for (let option of Object.keys(options)) {
60
62
  if (!optionKeys.includes(option)) {
61
63
  throw `${option} is not a valid configuration object.`
62
- + '\n For a list of available options, see https://github.com/abofs/chronicle#configuration';
64
+ + '\n For a list of available options, see https://github.com/abofs/stonyx-logs#configuration';
63
65
  }
64
66
 
65
67
  // sanitize path input
@@ -129,7 +131,9 @@ export default class Chronicle {
129
131
 
130
132
  async writeToFile(type, content, overwrite) {
131
133
  const path = this.getOptionForType(type, 'path');
132
- const targetLog = `${path}${type}.log`;
134
+ const filenameTemplate = this.getOptionForType(type, 'filename');
135
+ const resolvedName = this.resolveFilename(filenameTemplate, type);
136
+ const targetLog = `${path}${resolvedName}`;
133
137
  await this.validateFileAndDirectory(path, targetLog);
134
138
 
135
139
  const fileAction = overwrite ? fsp.writeFile : fsp.appendFile;
@@ -137,6 +141,31 @@ export default class Chronicle {
137
141
  return fileAction(targetLog, content);
138
142
  }
139
143
 
144
+ // resolves template variables in a filename string
145
+ resolveFilename(template, type) {
146
+ // default to '{type}.log' when no template is configured
147
+ if (!template) return `${type}.log`;
148
+
149
+ const now = new Date();
150
+ const yyyy = now.getFullYear();
151
+ const mm = String(now.getMonth() + 1).padStart(2, '0');
152
+ const dd = String(now.getDate()).padStart(2, '0');
153
+
154
+ const variables = {
155
+ date: `${yyyy}-${mm}-${dd}`,
156
+ type,
157
+ pid: process.pid,
158
+ hostname: hostname(),
159
+ };
160
+
161
+ const resolved = template.replace(/\{(\w+)\}/g, (match, key) => {
162
+ return variables[key] !== undefined ? variables[key] : match;
163
+ });
164
+
165
+ // sanitize: prevent path traversal and disallow directory separators
166
+ return resolved.replace(/\.\./g, '').replace(/[/\\]/g, '');
167
+ }
168
+
140
169
  // attempts to create file and/or directory if they don't already exist
141
170
  async validateFileAndDirectory(path, targetLog) {
142
171
  const errorMethod = this.error || console.error; // prefer native method unless removed by user