or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-logging.mdindex.mdlevel-control.mdmulti-logger.mdplugins.md

plugins.mddocs/

0

# Plugin System

1

2

Extend loglevel with custom logging behavior through the method factory system, enabling advanced features like remote logging, custom formatting, and output redirection.

3

4

## Capabilities

5

6

### methodFactory

7

8

```javascript { .api }

9

/**

10

* Plugin API entry point for custom method factories

11

* Called for each enabled method when level is set

12

* @type {MethodFactory}

13

*/

14

methodFactory: MethodFactory;

15

16

/**

17

* Method factory function type

18

* @param {string} methodName - Log method name ('trace', 'debug', 'info', 'warn', 'error')

19

* @param {number} level - Current logging level (0-5)

20

* @param {string | symbol} loggerName - Name of the logger (undefined for root logger)

21

* @returns {Function} Logging method implementation

22

*/

23

type MethodFactory = (

24

methodName: 'trace' | 'debug' | 'info' | 'warn' | 'error',

25

level: number,

26

loggerName: string | symbol | undefined

27

) => (...message: any[]) => void;

28

```

29

30

**Usage Examples:**

31

32

```javascript

33

import log from 'loglevel';

34

35

// Basic method factory override

36

const originalFactory = log.methodFactory;

37

log.methodFactory = function(methodName, level, loggerName) {

38

const rawMethod = originalFactory(methodName, level, loggerName);

39

40

return function(...args) {

41

// Add timestamp prefix

42

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

43

rawMethod(`[${timestamp}]`, ...args);

44

};

45

};

46

47

// Apply the factory

48

log.setLevel(log.getLevel()); // Rebuilds methods with new factory

49

log.info('This message has a timestamp'); // [2023-10-01T12:00:00.000Z] This message has a timestamp

50

```

51

52

### rebuild

53

54

```javascript { .api }

55

/**

56

* Rebuild logging methods using current methodFactory

57

* Forces regeneration of all logging methods

58

* Updates child loggers if called on root logger

59

*/

60

rebuild(): void;

61

```

62

63

**Usage Examples:**

64

65

```javascript

66

import log from 'loglevel';

67

68

// Change method factory

69

log.methodFactory = customFactory;

70

71

// Rebuild methods to apply changes

72

log.rebuild();

73

74

// For root logger, also rebuilds all child loggers

75

const childLogger = log.getLogger('child');

76

log.rebuild(); // Updates both root and child logger methods

77

```

78

79

## Plugin Examples

80

81

### Prefix Plugin

82

83

Add prefixes to all log messages:

84

85

```javascript

86

import log from 'loglevel';

87

88

function createPrefixPlugin(prefix) {

89

const originalFactory = log.methodFactory;

90

91

log.methodFactory = function(methodName, level, loggerName) {

92

const rawMethod = originalFactory(methodName, level, loggerName);

93

94

return function(...args) {

95

const loggerPrefix = loggerName ? `[${String(loggerName)}]` : '';

96

rawMethod(`${prefix}${loggerPrefix}`, ...args);

97

};

98

};

99

100

log.rebuild();

101

}

102

103

// Usage

104

createPrefixPlugin('[MyApp] ');

105

106

const dbLogger = log.getLogger('DB');

107

log.info('Application started'); // [MyApp] Application started

108

dbLogger.warn('Connection slow'); // [MyApp] [DB] Connection slow

109

```

110

111

### Remote Logging Plugin

112

113

Send logs to a remote server:

114

115

```javascript

116

import log from 'loglevel';

117

118

function createRemotePlugin(endpoint) {

119

const originalFactory = log.methodFactory;

120

121

log.methodFactory = function(methodName, level, loggerName) {

122

const rawMethod = originalFactory(methodName, level, loggerName);

123

124

return function(...args) {

125

// Local logging

126

rawMethod(...args);

127

128

// Remote logging for errors and warnings

129

if (level >= log.levels.WARN) {

130

fetch(endpoint, {

131

method: 'POST',

132

headers: { 'Content-Type': 'application/json' },

133

body: JSON.stringify({

134

level: methodName,

135

logger: loggerName,

136

message: args.join(' '),

137

timestamp: Date.now(),

138

url: window.location?.href

139

})

140

}).catch(err => {

141

// Fail silently to avoid logging loops

142

});

143

}

144

};

145

};

146

147

log.rebuild();

148

}

149

150

// Usage

151

createRemotePlugin('/api/logs');

152

log.error('Critical error'); // Logs locally AND sends to server

153

```

154

155

### Conditional Logging Plugin

156

157

Add conditional logging based on environment or feature flags:

158

159

```javascript

160

import log from 'loglevel';

161

162

function createConditionalPlugin(shouldLog) {

163

const originalFactory = log.methodFactory;

164

165

log.methodFactory = function(methodName, level, loggerName) {

166

const rawMethod = originalFactory(methodName, level, loggerName);

167

168

return function(...args) {

169

// Check condition before logging

170

if (shouldLog(methodName, level, loggerName, args)) {

171

rawMethod(...args);

172

}

173

};

174

};

175

176

log.rebuild();

177

}

178

179

// Usage examples

180

// Only log in development

181

createConditionalPlugin(() => process.env.NODE_ENV === 'development');

182

183

// Only log specific modules

184

createConditionalPlugin((method, level, logger) => {

185

return !logger || logger === 'database' || logger === 'api';

186

});

187

188

// Rate limiting

189

const logCounts = new Map();

190

createConditionalPlugin((method, level, logger, args) => {

191

const key = `${logger}-${method}`;

192

const count = logCounts.get(key) || 0;

193

logCounts.set(key, count + 1);

194

return count < 100; // Max 100 logs per method per logger

195

});

196

```

197

198

### Formatting Plugin

199

200

Custom message formatting and structured logging:

201

202

```javascript

203

import log from 'loglevel';

204

205

function createFormattingPlugin() {

206

const originalFactory = log.methodFactory;

207

208

log.methodFactory = function(methodName, level, loggerName) {

209

const rawMethod = originalFactory(methodName, level, loggerName);

210

211

return function(...args) {

212

// Structured logging format

213

const logEntry = {

214

timestamp: new Date().toISOString(),

215

level: methodName.toUpperCase(),

216

logger: loggerName || 'root',

217

message: args.length === 1 && typeof args[0] === 'string'

218

? args[0]

219

: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ')

220

};

221

222

// Format as JSON for structured logging

223

rawMethod(JSON.stringify(logEntry));

224

};

225

};

226

227

log.rebuild();

228

}

229

230

// Usage

231

createFormattingPlugin();

232

log.info('User logged in', { userId: 123 });

233

// {"timestamp":"2023-10-01T12:00:00.000Z","level":"INFO","logger":"root","message":"User logged in {\"userId\":123}"}

234

```

235

236

## Plugin Best Practices

237

238

### Preserve Original Functionality

239

240

Always wrap the original method factory to maintain loglevel's reliability:

241

242

```javascript

243

const originalFactory = log.methodFactory;

244

log.methodFactory = function(methodName, level, loggerName) {

245

const rawMethod = originalFactory(methodName, level, loggerName);

246

247

return function(...args) {

248

// Your custom logic here

249

try {

250

// Custom processing

251

processCustomLogic(methodName, args);

252

} catch (error) {

253

// Don't break logging if plugin fails

254

}

255

256

// Always call original method

257

return rawMethod(...args);

258

};

259

};

260

```

261

262

### Handle Errors Gracefully

263

264

Plugin failures shouldn't break logging:

265

266

```javascript

267

log.methodFactory = function(methodName, level, loggerName) {

268

const rawMethod = originalFactory(methodName, level, loggerName);

269

270

return function(...args) {

271

try {

272

// Plugin logic

273

customBehavior(...args);

274

} catch (error) {

275

// Silently fail or use fallback

276

console.error('Logging plugin error:', error);

277

}

278

279

return rawMethod(...args);

280

};

281

};

282

```

283

284

### Support All Loggers

285

286

Ensure plugins work with both root and named loggers:

287

288

```javascript

289

log.methodFactory = function(methodName, level, loggerName) {

290

const rawMethod = originalFactory(methodName, level, loggerName);

291

292

return function(...args) {

293

// Handle both root logger (loggerName === undefined) and named loggers

294

const prefix = loggerName ? `[${String(loggerName)}]` : '[ROOT]';

295

return rawMethod(prefix, ...args);

296

};

297

};

298

299

// Rebuild all loggers

300

log.rebuild();

301

```

302

303

### Memory Management

304

305

Be aware of memory usage in plugins:

306

307

```javascript

308

// Avoid memory leaks in stateful plugins

309

const logCache = new Map();

310

311

log.methodFactory = function(methodName, level, loggerName) {

312

const rawMethod = originalFactory(methodName, level, loggerName);

313

314

return function(...args) {

315

// Limit cache size

316

if (logCache.size > 1000) {

317

logCache.clear();

318

}

319

320

// Cache logic here

321

return rawMethod(...args);

322

};

323

};

324

```