or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-logging.mdenable-disable-control.mdindex.mdlog-writer-system.mdnamespace-management.mdutility-functions.md

log-writer-system.mddocs/

0

# Log Writer System

1

2

Abstract writer system for creating custom log output handlers. Writers subscribe to log events and handle actual output formatting and destination routing, enabling pluggable log output across different environments and platforms.

3

4

## Capabilities

5

6

### Abstract Writer Constructor

7

8

Base class for creating custom log writers that handle log output.

9

10

```javascript { .api }

11

/**

12

* Creates a log writer instance

13

* @param {object} env - Environment variables object

14

* @param {object} [options] - Optional configuration

15

* @param {string} [options.defaultNamespace] - Default namespace for logs

16

* @throws {Error} If called without 'new' keyword

17

*/

18

function LogWriter(env, options);

19

```

20

21

**Usage Examples:**

22

23

```javascript

24

const LogWriter = require("log/lib/abstract-writer");

25

26

// Basic writer setup

27

const writer = new LogWriter(process.env);

28

29

// Writer with options

30

const writer = new LogWriter(process.env, {

31

defaultNamespace: "myapp"

32

});

33

34

// Environment variables used:

35

// - LOG_LEVEL: threshold level (error, warning, notice, info, debug)

36

// - LOG_DEBUG: namespace-based debug filter

37

// - DEBUG: fallback debug filter

38

// - LOG_TIME: timestamp format configuration

39

```

40

41

### Static Properties

42

43

Class-level properties and methods for writer configuration.

44

45

```javascript { .api }

46

/**

47

* Maps log levels to display symbols/prefixes

48

* @type {object}

49

*/

50

LogWriter.levelPrefixes;

51

52

/**

53

* Resolves namespace message prefix for display

54

* @param {Logger} logger - Logger instance

55

* @returns {string|null} Namespace prefix or null

56

*/

57

LogWriter.resolveNamespaceMessagePrefix(logger);

58

```

59

60

**Usage Examples:**

61

62

```javascript

63

const LogWriter = require("log/lib/abstract-writer");

64

65

// Level symbols/prefixes

66

console.log(LogWriter.levelPrefixes);

67

// { debug: "●", info: "ℹ", notice: "ℹ", warning: "⚠", error: "✖" }

68

69

// Namespace prefix resolution

70

const log = require("log");

71

const appLogger = log.get("myapp:service");

72

73

const prefix = LogWriter.resolveNamespaceMessagePrefix(appLogger);

74

console.log(prefix); // "myapp:service" or shortened version

75

```

76

77

### Instance Methods

78

79

Methods available on writer instances for handling log events.

80

81

```javascript { .api }

82

/**

83

* Check if a logger is enabled for output

84

* @param {Logger} logger - Logger instance to check

85

* @returns {boolean} True if logger should output

86

*/

87

writer.isLoggerEnabled(logger);

88

89

/**

90

* Set up level-specific properties on logger

91

* @param {Logger} logger - Logger instance to configure

92

*/

93

writer.setupLevelLogger(logger);

94

95

/**

96

* Set up level message prefix on logger

97

* @param {Logger} logger - Logger instance to configure

98

*/

99

writer.setupLevelMessagePrefix(logger);

100

101

/**

102

* Abstract method - must be implemented by subclasses

103

* @param {LogEvent} event - Log event to write

104

*/

105

writer.writeMessage(event);

106

107

/**

108

* Resolve message tokens into formatted strings

109

* @param {LogEvent} event - Log event to process

110

*/

111

writer.resolveMessageTokens(event);

112

113

/**

114

* Resolve final message from tokens

115

* @param {LogEvent} event - Log event to process

116

*/

117

writer.resolveMessage(event);

118

```

119

120

### Master Writer Registration

121

122

Global writer registration system for managing the active log writer.

123

124

```javascript { .api }

125

/**

126

* Get the currently registered master writer

127

* @returns {LogWriter|null} Active writer or null

128

*/

129

function getMasterWriter();

130

131

/**

132

* Register a master log writer (only one allowed)

133

* @param {LogWriter} writer - Writer instance to register

134

* @returns {LogWriter} The registered writer

135

* @throws {Error} If master writer already registered or invalid writer

136

*/

137

getMasterWriter.register(writer);

138

```

139

140

**Usage Examples:**

141

142

```javascript

143

const getMasterWriter = require("log/lib/get-master-writer");

144

145

// Check current master writer

146

const currentWriter = getMasterWriter();

147

console.log(currentWriter); // null if none registered

148

149

// Register a new writer

150

const writer = new MyCustomWriter(process.env);

151

getMasterWriter.register(writer);

152

153

// Attempting to register another throws error

154

try {

155

getMasterWriter.register(anotherWriter);

156

} catch (e) {

157

console.log(e.message); // "Cannot register: Master log writer already registered"

158

}

159

```

160

161

## Event System

162

163

### Log Events

164

165

Writers receive log events through the global event emitter.

166

167

```javascript { .api }

168

/**

169

* Log event structure passed to writers

170

*/

171

interface LogEvent {

172

/** Logger instance that generated the event */

173

logger: Logger;

174

/** Array of message arguments passed to logger */

175

messageTokens: any[];

176

/** Resolved message string (set by writer) */

177

message?: string;

178

}

179

180

/**

181

* Init event structure for new logger initialization

182

*/

183

interface InitEvent {

184

/** Newly initialized logger instance */

185

logger: Logger;

186

}

187

```

188

189

### Event Emitter

190

191

Global event emitter for log system events.

192

193

```javascript { .api }

194

/**

195

* Global log event emitter

196

* Events:

197

* - 'log': Emitted when logger is called with message

198

* - 'init': Emitted when new logger is initialized

199

*/

200

const emitter = require("log/lib/emitter");

201

```

202

203

**Usage Examples:**

204

205

```javascript

206

const emitter = require("log/lib/emitter");

207

208

// Listen for log events

209

emitter.on("log", (event) => {

210

console.log("Log event:", {

211

level: event.logger.level,

212

namespace: event.logger.namespace,

213

tokens: event.messageTokens

214

});

215

});

216

217

// Listen for logger initialization

218

emitter.on("init", (event) => {

219

console.log("New logger:", {

220

level: event.logger.level,

221

namespace: event.logger.namespace

222

});

223

});

224

```

225

226

## Custom Writer Implementation

227

228

### Basic Writer Example

229

230

```javascript

231

const LogWriter = require("log/lib/abstract-writer");

232

233

class ConsoleWriter extends LogWriter {

234

constructor(env, options) {

235

super(env, options);

236

}

237

238

writeMessage(event) {

239

const { logger, message } = event;

240

241

// Get level prefix

242

const levelPrefix = this.constructor.levelPrefixes[logger.level];

243

244

// Get namespace prefix

245

const namespacePrefix = this.constructor.resolveNamespaceMessagePrefix(logger);

246

247

// Format output

248

let output = `${levelPrefix} `;

249

if (namespacePrefix) {

250

output += `[${namespacePrefix}] `;

251

}

252

output += message;

253

254

// Write to console

255

console.log(output);

256

}

257

}

258

259

// Initialize writer

260

new ConsoleWriter(process.env);

261

```

262

263

### Advanced Writer Features

264

265

```javascript

266

class AdvancedWriter extends LogWriter {

267

constructor(env, options) {

268

super(env, options);

269

this.logFile = options?.logFile;

270

}

271

272

writeMessage(event) {

273

const { logger } = event;

274

275

// Custom filtering

276

if (!this.shouldLog(logger)) {

277

return;

278

}

279

280

// Custom formatting

281

const formattedMessage = this.formatMessage(event);

282

283

// Multiple outputs

284

console.log(formattedMessage);

285

286

if (this.logFile) {

287

this.writeToFile(formattedMessage);

288

}

289

}

290

291

shouldLog(logger) {

292

// Custom logic for log filtering

293

return logger.isEnabled && logger.levelIndex <= 2;

294

}

295

296

formatMessage(event) {

297

const timestamp = new Date().toISOString();

298

const { logger, message } = event;

299

300

return `${timestamp} [${logger.level.toUpperCase()}] ${logger.namespace || 'ROOT'}: ${message}`;

301

}

302

303

writeToFile(message) {

304

// File writing logic

305

require('fs').appendFileSync(this.logFile, message + '\n');

306

}

307

}

308

```

309

310

## Environment Configuration

311

312

### Environment Variables

313

314

Writers use environment variables for configuration:

315

316

```javascript

317

// LOG_LEVEL: Sets visibility threshold

318

// Values: error, warning, notice, info, debug

319

// Default: notice

320

process.env.LOG_LEVEL = "info";

321

322

// LOG_DEBUG: Namespace-based debug filtering

323

// Format: comma-separated namespaces, "-" prefix to disable

324

// Examples: "myapp", "service:*", "db,-db:verbose"

325

process.env.LOG_DEBUG = "myapp:service,database";

326

327

// DEBUG: Fallback debug filter (debug-lib compatible)

328

process.env.DEBUG = "myapp:*";

329

330

// LOG_TIME: Timestamp configuration

331

// Implementation-specific format

332

process.env.LOG_TIME = "iso";

333

```

334

335

### Visibility Control

336

337

Writers automatically apply visibility control based on level thresholds and namespace filters:

338

339

```javascript

340

const LogWriter = require("log/lib/abstract-writer");

341

342

// Environment setup

343

process.env.LOG_LEVEL = "notice"; // Show notice and above

344

process.env.LOG_DEBUG = "myapp"; // Also show debug logs for "myapp" namespace

345

346

const writer = new MyWriter(process.env);

347

348

// These will be visible (notice and above):

349

log.error("Error message"); // ✓ Visible (error >= notice)

350

log.warning("Warning"); // ✓ Visible (warning >= notice)

351

log.notice("Notice"); // ✓ Visible (notice >= notice)

352

353

// These will be hidden (below notice threshold):

354

log.info("Info message"); // ✗ Hidden (info < notice)

355

log.debug("Debug message"); // ✗ Hidden (debug < notice)

356

357

// But debug namespace is enabled:

358

log.get("myapp").debug("Debug in myapp"); // ✓ Visible (namespace filter)

359

```