or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-logging.mdindex.mdmarkers.mdmessage-system.mdperformance-features.mdspi.mdstatus-system.mdthread-context.md

message-system.mddocs/

0

# Message System & Formatting

1

2

Comprehensive message creation system supporting multiple formatting syntaxes, structured data, flow tracing, and custom message factories for specialized use cases.

3

4

## Capabilities

5

6

### Message Interface

7

8

Base interface for all log message types providing formatted output and metadata access.

9

10

```java { .api }

11

/**

12

* Base interface for all log message types

13

*/

14

public interface Message extends Serializable {

15

/** Get the formatted message string */

16

String getFormattedMessage();

17

18

/** Get message parameters array */

19

Object[] getParameters();

20

21

/** Get associated throwable if any */

22

Throwable getThrowable();

23

24

/** @Deprecated Get message format string */

25

@Deprecated

26

String getFormat();

27

}

28

```

29

30

**Usage Examples:**

31

32

```java

33

private static final Logger logger = LogManager.getLogger();

34

35

public void demonstrateMessageInterface() {

36

// Messages are typically created internally by the logging framework

37

// but can be created explicitly for advanced use cases

38

39

Message simpleMsg = new SimpleMessage("Hello World");

40

logger.info(simpleMsg);

41

42

Message paramMsg = new ParameterizedMessage("User {} has {} items", "alice", 5);

43

logger.info(paramMsg);

44

45

// Access message components

46

String formatted = paramMsg.getFormattedMessage(); // "User alice has 5 items"

47

Object[] params = paramMsg.getParameters(); // ["alice", 5]

48

}

49

```

50

51

### MessageFactory Interface

52

53

Factory for creating Message instances with different formatting syntaxes.

54

55

```java { .api }

56

/**

57

* Factory interface for creating Message instances

58

*/

59

public interface MessageFactory {

60

/** Create message from object */

61

Message newMessage(Object message);

62

63

/** Create message from string */

64

Message newMessage(String message);

65

66

/** Create parameterized message */

67

Message newMessage(String message, Object... params);

68

}

69

70

/**

71

* Extended message factory with additional methods

72

*/

73

public interface MessageFactory2 extends MessageFactory {

74

/** Create message from string with single parameter */

75

Message newMessage(String message, Object p0);

76

77

/** Create message from string with two parameters */

78

Message newMessage(String message, Object p0, Object p1);

79

80

// Additional overloads for up to 10 parameters for performance

81

Message newMessage(String message, Object p0, Object p1, Object p2);

82

// ... more overloads

83

}

84

```

85

86

**Usage Examples:**

87

88

```java

89

public void demonstrateMessageFactories() {

90

// Different message factories create different message types

91

92

// Parameterized message factory (default, uses {} placeholders)

93

MessageFactory paramFactory = ParameterizedMessageFactory.INSTANCE;

94

Message msg1 = paramFactory.newMessage("User {} logged in", "alice");

95

96

// String formatter message factory (uses String.format style)

97

MessageFactory stringFactory = StringFormatterMessageFactory.INSTANCE;

98

Message msg2 = stringFactory.newMessage("User %s has %d items", "alice", 5);

99

100

// Simple message factory (no parameter substitution)

101

MessageFactory simpleFactory = SimpleMessageFactory.INSTANCE;

102

Message msg3 = simpleFactory.newMessage("Simple message");

103

104

// Reusable message factory (for high-performance scenarios)

105

MessageFactory reusableFactory = ReusableMessageFactory.INSTANCE;

106

Message msg4 = reusableFactory.newMessage("Reusable: {}", value);

107

}

108

109

// Custom message factory

110

public class CustomMessageFactory implements MessageFactory {

111

112

@Override

113

public Message newMessage(Object message) {

114

return new CustomMessage(message);

115

}

116

117

@Override

118

public Message newMessage(String message) {

119

return new CustomMessage(message);

120

}

121

122

@Override

123

public Message newMessage(String message, Object... params) {

124

return new CustomParameterizedMessage(message, params);

125

}

126

}

127

```

128

129

### Core Message Types

130

131

Built-in message implementations for different formatting and data representation needs.

132

133

```java { .api }

134

/**

135

* Simple string message without parameter substitution

136

*/

137

public class SimpleMessage implements CharSequence, Message {

138

public SimpleMessage(CharSequence message);

139

public SimpleMessage(Object message);

140

}

141

142

/**

143

* Message with {} parameter placeholders (most commonly used)

144

*/

145

public class ParameterizedMessage implements Message {

146

public ParameterizedMessage(String messagePattern, Object[] arguments);

147

public ParameterizedMessage(String messagePattern, Object... arguments);

148

public ParameterizedMessage(String messagePattern, Object arg);

149

public ParameterizedMessage(String messagePattern, Object arg1, Object arg2);

150

151

/** Get count of parameters */

152

public int getParameterCount();

153

154

/** Get the message pattern */

155

public String getFormat();

156

157

/** Get throwable if last parameter is Throwable */

158

@Override

159

public Throwable getThrowable();

160

}

161

162

/**

163

* Message wrapping arbitrary objects

164

*/

165

public class ObjectMessage implements Message {

166

public ObjectMessage(Object obj);

167

168

/** Get the wrapped object */

169

public Object getParameter();

170

}

171

172

/**

173

* Message using String.format() style formatting

174

*/

175

public class StringFormattedMessage implements Message {

176

public StringFormattedMessage(String messagePattern, Object... arguments);

177

}

178

179

/**

180

* @Deprecated Message using java.text.MessageFormat

181

*/

182

@Deprecated

183

public class FormattedMessage implements Message {

184

public FormattedMessage(String messagePattern, Object... arguments);

185

}

186

```

187

188

**Usage Examples:**

189

190

```java

191

private static final Logger logger = LogManager.getLogger();

192

193

public void demonstrateMessageTypes() {

194

// Simple message - no parameter substitution

195

SimpleMessage simple = new SimpleMessage("Simple log message");

196

logger.info(simple);

197

198

// Parameterized message - {} placeholders (most efficient)

199

ParameterizedMessage param = new ParameterizedMessage(

200

"User {} performed {} action at {}", "alice", "login", new Date());

201

logger.info(param);

202

203

// Object message - wraps any object

204

ObjectMessage objMsg = new ObjectMessage(new UserProfile("alice", 25));

205

logger.info(objMsg); // Uses object's toString()

206

207

// String formatted message - String.format() style

208

StringFormattedMessage formatted = new StringFormattedMessage(

209

"User %s has %d items (%.2f%% complete)", "alice", 5, 75.5);

210

logger.info(formatted);

211

212

// Automatic throwable detection in parameterized messages

213

Exception ex = new RuntimeException("test");

214

ParameterizedMessage withEx = new ParameterizedMessage(

215

"Error processing user {}", "alice", ex); // Exception automatically extracted

216

logger.error(withEx); // Exception will be logged separately

217

218

// Access message properties

219

String pattern = param.getFormat(); // Original pattern: "User {} performed {} action at {}"

220

Object[] params = param.getParameters(); // ["alice", "login", Date]

221

int paramCount = param.getParameterCount(); // 3

222

}

223

224

// Custom object message usage

225

public class UserProfile {

226

private String name;

227

private int age;

228

229

public UserProfile(String name, int age) {

230

this.name = name;

231

this.age = age;

232

}

233

234

@Override

235

public String toString() {

236

return String.format("UserProfile{name='%s', age=%d}", name, age);

237

}

238

}

239

240

public void logUserProfile() {

241

UserProfile profile = new UserProfile("alice", 25);

242

243

// Object message will use toString()

244

logger.info(new ObjectMessage(profile));

245

// Output: UserProfile{name='alice', age=25}

246

247

// Parameterized message with object

248

logger.info("User profile: {}", profile);

249

// Output: User profile: UserProfile{name='alice', age=25}

250

}

251

```

252

253

### Structured Data Messages

254

255

Messages that represent structured key-value data, particularly useful for logging events and metrics.

256

257

```java { .api }

258

/**

259

* Message representing key-value pairs

260

*/

261

public class MapMessage implements Message {

262

public MapMessage();

263

public MapMessage(Map<String, Object> map);

264

265

/** Put a key-value pair */

266

public MapMessage with(String key, Object value);

267

268

/** Put a key-value pair (fluent API) */

269

public MapMessage put(String key, Object value);

270

271

/** Get value by key */

272

public Object get(String key);

273

274

/** Remove key */

275

public Object remove(String key);

276

277

/** Get all keys */

278

public String[] getKeys();

279

280

/** Check if key exists */

281

public boolean containsKey(String key);

282

283

/** Get as Map */

284

public Map<String, Object> getData();

285

286

/** Clear all data */

287

public void clear();

288

}

289

290

/**

291

* RFC 5424 Structured Data message

292

*/

293

public class StructuredDataMessage extends MapMessage {

294

public StructuredDataMessage(String id, Map<String, String> data, String message);

295

public StructuredDataMessage(String id, Map<String, String> data, String message, Object... args);

296

297

/** Get structured data ID */

298

public String getId();

299

300

/** Get structured data as RFC 5424 format */

301

public String asString();

302

303

/** Get structured data as RFC 5424 format with specified format */

304

public String asString(String format);

305

}

306

```

307

308

**Usage Examples:**

309

310

```java

311

private static final Logger logger = LogManager.getLogger();

312

313

public void demonstrateStructuredMessages() {

314

// Map message for structured logging

315

MapMessage mapMsg = new MapMessage()

316

.with("userId", "12345")

317

.with("action", "login")

318

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

319

.with("success", true)

320

.with("duration", 150);

321

322

logger.info(mapMsg);

323

// Output: userId="12345" action="login" timestamp="1634567890123" success="true" duration="150"

324

325

// Structured data message (RFC 5424 compliant)

326

Map<String, String> eventData = new HashMap<>();

327

eventData.put("userId", "12345");

328

eventData.put("sessionId", "abc-def-ghi");

329

eventData.put("remoteAddr", "192.168.1.100");

330

331

StructuredDataMessage sdMsg = new StructuredDataMessage(

332

"loginEvent", eventData, "User {} logged in successfully", "alice");

333

334

logger.info(sdMsg);

335

// Output: [loginEvent userId="12345" sessionId="abc-def-ghi" remoteAddr="192.168.1.100"] User alice logged in successfully

336

337

// Building map messages fluently

338

MapMessage auditMsg = new MapMessage()

339

.put("event", "fileAccess")

340

.put("file", "/etc/passwd")

341

.put("user", "admin")

342

.put("result", "denied");

343

344

logger.warn(auditMsg);

345

}

346

347

// Business event logging with structured data

348

public class EventLogger {

349

private static final Logger logger = LogManager.getLogger();

350

351

public void logUserAction(String userId, String action, boolean successful, long duration) {

352

MapMessage event = new MapMessage()

353

.with("userId", userId)

354

.with("action", action)

355

.with("successful", successful)

356

.with("duration", duration)

357

.with("timestamp", Instant.now().toString());

358

359

if (successful) {

360

logger.info(event);

361

} else {

362

logger.warn(event);

363

}

364

}

365

366

public void logOrderEvent(Order order, String event) {

367

StructuredDataMessage sdMsg = new StructuredDataMessage(

368

"orderEvent",

369

Map.of(

370

"orderId", order.getId(),

371

"customerId", order.getCustomerId(),

372

"amount", order.getAmount().toString(),

373

"currency", order.getCurrency()

374

),

375

"Order {} event: {}", order.getId(), event);

376

377

logger.info(sdMsg);

378

}

379

}

380

```

381

382

### Flow Messages

383

384

Specialized messages for method entry/exit tracing and flow control logging.

385

386

```java { .api }

387

/**

388

* Message for method entry logging

389

*/

390

public class EntryMessage implements Message {

391

public EntryMessage(String format, Object... params);

392

393

/** Get the message for entry */

394

public Message getMessage();

395

}

396

397

/**

398

* Message for method exit logging

399

*/

400

public class ExitMessage implements Message {

401

public ExitMessage(EntryMessage message, Object result, long durationNanos);

402

public ExitMessage(String format, Object result, long durationNanos);

403

404

/** Get the result object */

405

public Object getResult();

406

407

/** Get execution duration in nanoseconds */

408

public long getDurationNanos();

409

410

/** Get the entry message */

411

public EntryMessage getEntryMessage();

412

}

413

414

/**

415

* Factory for creating flow messages

416

*/

417

public interface FlowMessageFactory {

418

EntryMessage newEntryMessage(Message message);

419

ExitMessage newExitMessage(EntryMessage message, Object result, long durationNanos);

420

ExitMessage newExitMessage(Object result, Message message);

421

}

422

423

/**

424

* Default flow message factory implementation

425

*/

426

public class DefaultFlowMessageFactory implements FlowMessageFactory {

427

public static final DefaultFlowMessageFactory INSTANCE = new DefaultFlowMessageFactory();

428

}

429

```

430

431

**Usage Examples:**

432

433

```java

434

private static final Logger logger = LogManager.getLogger();

435

436

public class FlowTrackingService {

437

438

// Manual flow message creation

439

public String processUser(String userId) {

440

EntryMessage entryMsg = new EntryMessage("processUser(userId={})", userId);

441

logger.traceEntry(entryMsg);

442

443

long startTime = System.nanoTime();

444

try {

445

// Process user

446

String result = "processed-" + userId;

447

448

long duration = System.nanoTime() - startTime;

449

ExitMessage exitMsg = new ExitMessage(entryMsg, result, duration);

450

logger.traceExit(exitMsg);

451

452

return result;

453

454

} catch (Exception e) {

455

logger.throwing(e);

456

throw e;

457

}

458

}

459

460

// Using Logger's built-in flow methods (preferred)

461

public User findUser(Long id) {

462

logger.traceEntry("findUser(id={})", id);

463

464

try {

465

User user = userRepository.findById(id);

466

return logger.traceExit(user);

467

} catch (Exception e) {

468

throw logger.throwing(e);

469

}

470

}

471

472

// Complex flow with multiple parameters

473

public Order createOrder(String customerId, List<OrderItem> items, PaymentInfo payment) {

474

logger.traceEntry("customerId={}, itemCount={}, paymentMethod={}",

475

customerId, items.size(), payment.getMethod());

476

477

try {

478

validateCustomer(customerId);

479

validateItems(items);

480

validatePayment(payment);

481

482

Order order = new Order(customerId, items, payment);

483

Order savedOrder = orderRepository.save(order);

484

485

return logger.traceExit(savedOrder);

486

487

} catch (Exception e) {

488

throw logger.throwing(e);

489

}

490

}

491

492

// Flow tracking with custom flow message factory

493

private static final FlowMessageFactory flowFactory = DefaultFlowMessageFactory.INSTANCE;

494

495

public void customFlowTracking() {

496

Message entryMessage = new SimpleMessage("Starting custom operation");

497

EntryMessage entry = flowFactory.newEntryMessage(entryMessage);

498

logger.trace(entry);

499

500

long startTime = System.nanoTime();

501

try {

502

String result = performOperation();

503

504

long duration = System.nanoTime() - startTime;

505

ExitMessage exit = flowFactory.newExitMessage(entry, result, duration);

506

logger.trace(exit);

507

508

} catch (Exception e) {

509

logger.error("Operation failed", e);

510

throw e;

511

}

512

}

513

}

514

```

515

516

### Advanced Message Features

517

518

Specialized message interfaces for performance optimization and async-safe formatting.

519

520

```java { .api }

521

/**

522

* Messages supporting multiple output formats

523

*/

524

public interface MultiformatMessage {

525

/** Get formatted message for specific format */

526

String getFormattedMessage(String[] formats);

527

}

528

529

/**

530

* Messages that can be reused to avoid object allocation

531

*/

532

public interface ReusableMessage extends Message, Clearable {

533

/** Set new message content */

534

ReusableMessage set(String message);

535

536

/** Set new parameterized message content */

537

ReusableMessage set(String message, Object... params);

538

539

/** Swap contents with another reusable message */

540

void swapParameters(ReusableMessage other);

541

}

542

543

/**

544

* Messages safe for asynchronous formatting

545

*/

546

public interface AsynchronouslyFormattable {

547

/** Format message asynchronously without blocking */

548

String[] formatTo(StringBuilder[] buffers);

549

}

550

551

/**

552

* Messages that can be cleared/reset

553

*/

554

public interface Clearable {

555

/** Clear message content */

556

void clear();

557

}

558

559

/**

560

* Messages with embedded timestamps

561

*/

562

public interface TimestampMessage {

563

/** Get message timestamp */

564

long getTimestamp();

565

}

566

567

/**

568

* Messages aware of the logger name

569

*/

570

public interface LoggerNameAwareMessage {

571

/** Set logger name */

572

void setLoggerName(String name);

573

574

/** Get logger name */

575

String getLoggerName();

576

}

577

```

578

579

**Usage Examples:**

580

581

```java

582

public void demonstrateAdvancedMessageFeatures() {

583

// Reusable messages for high-performance scenarios

584

ReusableMessage reusableMsg = new ReusableParameterizedMessage();

585

586

for (int i = 0; i < 1000; i++) {

587

reusableMsg.set("Processing item {}", i);

588

logger.debug(reusableMsg);

589

reusableMsg.clear(); // Reset for reuse

590

}

591

592

// Multiformat messages

593

MultiformatMessage multiMsg = new CustomMultiFormatMessage("base message");

594

String xmlFormat = multiMsg.getFormattedMessage(new String[]{"xml"});

595

String jsonFormat = multiMsg.getFormattedMessage(new String[]{"json"});

596

597

// Timestamp-aware messages

598

TimestampMessage timestampMsg = new CustomTimestampMessage("Event occurred");

599

long eventTime = timestampMsg.getTimestamp();

600

601

// Logger-name-aware messages

602

LoggerNameAwareMessage loggerAwareMsg = new CustomLoggerAwareMessage("message");

603

loggerAwareMsg.setLoggerName("com.example.MyClass");

604

}

605

606

// Custom async-safe message for high-throughput scenarios

607

public class AsyncSafeMessage implements Message, AsynchronouslyFormattable {

608

private final String pattern;

609

private final Object[] parameters;

610

611

public AsyncSafeMessage(String pattern, Object... parameters) {

612

this.pattern = pattern;

613

this.parameters = parameters.clone(); // Safe copy for async access

614

}

615

616

@Override

617

public String getFormattedMessage() {

618

return ParameterizedMessage.format(pattern, parameters);

619

}

620

621

@Override

622

public String[] formatTo(StringBuilder[] buffers) {

623

// Format to provided buffers for async processing

624

String formatted = getFormattedMessage();

625

buffers[0].append(formatted);

626

return new String[]{formatted};

627

}

628

629

@Override

630

public Object[] getParameters() {

631

return parameters.clone(); // Return safe copy

632

}

633

634

@Override

635

public Throwable getThrowable() {

636

// Check if last parameter is throwable

637

if (parameters.length > 0 && parameters[parameters.length - 1] instanceof Throwable) {

638

return (Throwable) parameters[parameters.length - 1];

639

}

640

return null;

641

}

642

}

643

```