or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-logging.mdfluent-logging.mdindex.mdmarkers.mdmdc.mdservice-providers.md

fluent-logging.mddocs/

0

# Fluent Logging API

1

2

SLF4J 2.0 introduces a modern fluent API that provides a chainable interface for building complex log statements. This API supports structured logging with key-value pairs, lazy evaluation, and builder pattern for enhanced logging capabilities.

3

4

## Capabilities

5

6

### Fluent Entry Points

7

8

Logger methods that return LoggingEventBuilder instances for chainable operations.

9

10

```java { .api }

11

/**

12

* Entry point for fluent-logging for TRACE level

13

* @return LoggingEventBuilder instance as appropriate for level TRACE

14

*/

15

LoggingEventBuilder atTrace();

16

17

/**

18

* Entry point for fluent-logging for DEBUG level

19

* @return LoggingEventBuilder instance as appropriate for level DEBUG

20

*/

21

LoggingEventBuilder atDebug();

22

23

/**

24

* Entry point for fluent-logging for INFO level

25

* @return LoggingEventBuilder instance as appropriate for level INFO

26

*/

27

LoggingEventBuilder atInfo();

28

29

/**

30

* Entry point for fluent-logging for WARN level

31

* @return LoggingEventBuilder instance as appropriate for level WARN

32

*/

33

LoggingEventBuilder atWarn();

34

35

/**

36

* Entry point for fluent-logging for ERROR level

37

* @return LoggingEventBuilder instance as appropriate for level ERROR

38

*/

39

LoggingEventBuilder atError();

40

41

/**

42

* Entry point for fluent-logging for any level

43

* @param level desired level for the event builder

44

* @return LoggingEventBuilder instance as appropriate for the specified level

45

*/

46

LoggingEventBuilder atLevel(Level level);

47

48

/**

49

* Check if logger is enabled for the specified level

50

* @param level the level to check

51

* @return true if enabled, false otherwise

52

*/

53

boolean isEnabledForLevel(Level level);

54

```

55

56

### LoggingEventBuilder Interface

57

58

Main interface for building structured log events with method chaining.

59

60

```java { .api }

61

/**

62

* Main interface for creating logging events with fluent API

63

*/

64

public interface LoggingEventBuilder {

65

/**

66

* Set the cause for the logging event being built

67

* @param cause a throwable

68

* @return a LoggingEventBuilder, usually this

69

*/

70

LoggingEventBuilder setCause(Throwable cause);

71

72

/**

73

* Add a Marker to the event being built

74

* @param marker a Marker instance to add

75

* @return a LoggingEventBuilder, usually this

76

*/

77

LoggingEventBuilder addMarker(Marker marker);

78

79

/**

80

* Add an argument to the event being built

81

* @param p an Object to add

82

* @return a LoggingEventBuilder, usually this

83

*/

84

LoggingEventBuilder addArgument(Object p);

85

86

/**

87

* Add an argument supplier to the event being built

88

* @param objectSupplier an Object supplier to add

89

* @return a LoggingEventBuilder, usually this

90

*/

91

LoggingEventBuilder addArgument(Supplier<?> objectSupplier);

92

93

/**

94

* Add a key value pair to the event being built

95

* @param key the key of the key value pair

96

* @param value the value of the key value pair

97

* @return a LoggingEventBuilder, usually this

98

*/

99

LoggingEventBuilder addKeyValue(String key, Object value);

100

101

/**

102

* Add a key value pair to the event being built

103

* @param key the key of the key value pair

104

* @param valueSupplier a supplier of a value for the key value pair

105

* @return a LoggingEventBuilder, usually this

106

*/

107

LoggingEventBuilder addKeyValue(String key, Supplier<Object> valueSupplier);

108

109

/**

110

* Sets the message of the logging event

111

* @param message the message string

112

* @return a LoggingEventBuilder, usually this

113

*/

114

LoggingEventBuilder setMessage(String message);

115

116

/**

117

* Sets the message of the event via a message supplier

118

* @param messageSupplier supplies a String to be used as the message

119

* @return a LoggingEventBuilder, usually this

120

*/

121

LoggingEventBuilder setMessage(Supplier<String> messageSupplier);

122

123

/**

124

* After the logging event is built, performs actual logging

125

*/

126

void log();

127

128

/**

129

* Equivalent to calling setMessage(String) followed by log()

130

* @param message the message to log

131

*/

132

void log(String message);

133

134

/**

135

* Equivalent to calling setMessage(String) followed by addArgument(Object) and then log()

136

* @param message the message to log

137

* @param arg an argument to be used with the message to log

138

*/

139

void log(String message, Object arg);

140

141

/**

142

* Equivalent to calling setMessage(String) followed by two calls to addArgument(Object) and then log()

143

* @param message the message to log

144

* @param arg0 first argument to be used with the message to log

145

* @param arg1 second argument to be used with the message to log

146

*/

147

void log(String message, Object arg0, Object arg1);

148

149

/**

150

* Equivalent to calling setMessage(String) followed by zero or more calls to addArgument(Object) and then log()

151

* @param message the message to log

152

* @param args a list (actually an array) of arguments to be used with the message to log

153

*/

154

void log(String message, Object... args);

155

156

/**

157

* Equivalent to calling setMessage(Supplier) followed by log()

158

* @param messageSupplier a Supplier returning a message of type String

159

*/

160

void log(Supplier<String> messageSupplier);

161

}

162

```

163

164

### Level Enumeration

165

166

Enumeration representing logging levels.

167

168

```java { .api }

169

/**

170

* SLF4J's internal representation of Level

171

*/

172

public enum Level {

173

ERROR, WARN, INFO, DEBUG, TRACE;

174

175

/**

176

* Get integer representation of the level

177

* @return the integer value

178

*/

179

int toInt();

180

181

/**

182

* Convert integer to Level

183

* @param levelInt the integer representation

184

* @return the corresponding Level

185

*/

186

static Level intToLevel(int levelInt);

187

}

188

```

189

190

**Usage Examples:**

191

192

```java

193

import org.slf4j.Logger;

194

import org.slf4j.LoggerFactory;

195

import org.slf4j.event.Level;

196

import java.util.function.Supplier;

197

198

public class FluentLoggingExample {

199

private static final Logger logger = LoggerFactory.getLogger(FluentLoggingExample.class);

200

201

public void basicFluentLogging() {

202

// Simple fluent logging

203

logger.atInfo().log("Application started");

204

205

// With arguments

206

logger.atDebug()

207

.addArgument("user123")

208

.addArgument(42)

209

.log("User {} has {} active sessions");

210

211

// With key-value pairs for structured logging

212

logger.atInfo()

213

.addKeyValue("userId", "user123")

214

.addKeyValue("action", "login")

215

.addKeyValue("timestamp", System.currentTimeMillis())

216

.log("User login event");

217

}

218

219

public void advancedFluentLogging() {

220

// Complex event building

221

try {

222

processOrder();

223

} catch (Exception e) {

224

logger.atError()

225

.addKeyValue("orderId", "ORD-12345")

226

.addKeyValue("customerId", "CUST-67890")

227

.addKeyValue("errorType", e.getClass().getSimpleName())

228

.setCause(e)

229

.log("Failed to process order");

230

}

231

232

// Conditional logging with level checking

233

if (logger.isEnabledForLevel(Level.TRACE)) {

234

logger.atTrace()

235

.setMessage(() -> buildExpensiveDebugMessage())

236

.log();

237

}

238

239

// Using suppliers for lazy evaluation

240

logger.atDebug()

241

.addArgument(() -> getCurrentUser().getName())

242

.addKeyValue("memoryUsage", () -> getMemoryUsage())

243

.log("Processing request for user {}");

244

}

245

246

public void markerBasedFluentLogging() {

247

Marker securityMarker = MarkerFactory.getMarker("SECURITY");

248

Marker auditMarker = MarkerFactory.getMarker("AUDIT");

249

250

// Multiple markers with fluent API

251

logger.atWarn()

252

.addMarker(securityMarker)

253

.addMarker(auditMarker)

254

.addKeyValue("userId", "user123")

255

.addKeyValue("attemptedAction", "admin_access")

256

.log("Unauthorized access attempt");

257

}

258

259

private String buildExpensiveDebugMessage() {

260

// Expensive operation only executed if TRACE is enabled

261

return "Complex debug info: " + performExpensiveCalculation();

262

}

263

264

private long getMemoryUsage() {

265

return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

266

}

267

}

268

```

269

270

### Structured Logging with Key-Value Pairs

271

272

The fluent API enables structured logging through key-value pairs:

273

274

```java

275

// Traditional logging - unstructured

276

logger.info("User john.doe logged in from IP 192.168.1.100 at 2023-12-01T10:30:00Z");

277

278

// Fluent API - structured logging

279

logger.atInfo()

280

.addKeyValue("event", "user_login")

281

.addKeyValue("username", "john.doe")

282

.addKeyValue("sourceIp", "192.168.1.100")

283

.addKeyValue("timestamp", "2023-12-01T10:30:00Z")

284

.log("User login event");

285

```

286

287

### Lazy Evaluation

288

289

The fluent API supports lazy evaluation using Supplier interfaces:

290

291

```java

292

// Expensive operation only executed if logging level is enabled

293

logger.atTrace()

294

.addArgument(() -> performExpensiveDatabaseQuery())

295

.addKeyValue("metrics", () -> calculateComplexMetrics())

296

.setMessage(() -> generateDetailedReport())

297

.log();

298

299

// Conditional logging is handled automatically

300

logger.atDebug()

301

.addArgument(() -> {

302

// This lambda is only executed if DEBUG level is enabled

303

return performExpensiveFormatting(data);

304

})

305

.log("Processed data: {}");

306

```

307

308

### Performance Benefits

309

310

The fluent API provides several performance advantages:

311

312

1. **Level Checking**: If the logging level is disabled, a no-operation LoggingEventBuilder is returned, avoiding any parameter evaluation

313

2. **Lazy Evaluation**: Suppliers are only invoked if logging will actually occur

314

3. **Efficient Builder**: The builder pattern minimizes object creation compared to traditional string concatenation

315

4. **Structured Data**: Key-value pairs enable efficient processing by logging backends without string parsing

316

317

### Migration from Traditional API

318

319

The fluent API can be gradually adopted alongside traditional logging:

320

321

```java

322

// Traditional approach

323

if (logger.isDebugEnabled()) {

324

logger.debug("Processing order {} for customer {} with total {}",

325

order.getId(), customer.getName(), order.getTotal());

326

}

327

328

// Fluent approach - level checking is automatic

329

logger.atDebug()

330

.addArgument(order.getId())

331

.addArgument(customer.getName())

332

.addArgument(order.getTotal())

333

.log("Processing order {} for customer {} with total {}");

334

335

// Or more structured

336

logger.atDebug()

337

.addKeyValue("orderId", order.getId())

338

.addKeyValue("customerId", customer.getId())

339

.addKeyValue("customerName", customer.getName())

340

.addKeyValue("orderTotal", order.getTotal())

341

.log("Processing order");

342

```

343

344

## Types

345

346

### Key-Value Pair Support

347

348

```java { .api }

349

/**

350

* Key-value pair for structured logging

351

*/

352

public class KeyValuePair {

353

public final String key;

354

public final Object value;

355

356

/**

357

* Create a key-value pair

358

* @param key the key

359

* @param value the value

360

*/

361

public KeyValuePair(String key, Object value);

362

}

363

```

364

365

### Event Constants

366

367

```java { .api }

368

/**

369

* Integer constants for log levels

370

*/

371

public class EventConstants {

372

public static final int ERROR_INT = 40;

373

public static final int WARN_INT = 30;

374

public static final int INFO_INT = 20;

375

public static final int DEBUG_INT = 10;

376

public static final int TRACE_INT = 0;

377

}

378

```