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

status-system.mddocs/

0

# Status & Error Handling

1

2

Internal status reporting system for Log4j configuration issues, initialization problems, and runtime diagnostics. Essential for troubleshooting logging setup.

3

4

## Capabilities

5

6

### StatusLogger

7

8

Internal logger for Log4j status messages and diagnostics.

9

10

```java { .api }

11

/**

12

* Logger for Log4j internal status messages

13

*/

14

public class StatusLogger implements Logger {

15

/** Get the status logger instance */

16

public static StatusLogger getLogger();

17

18

// Implements all Logger interface methods for internal status logging

19

@Override

20

public void trace(String message);

21

@Override

22

public void debug(String message);

23

@Override

24

public void info(String message);

25

@Override

26

public void warn(String message);

27

@Override

28

public void error(String message);

29

@Override

30

public void fatal(String message);

31

32

// Parameterized logging for status messages

33

@Override

34

public void info(String message, Object... params);

35

@Override

36

public void warn(String message, Object... params);

37

@Override

38

public void error(String message, Object... params);

39

40

// Level checking

41

@Override

42

public boolean isInfoEnabled();

43

@Override

44

public boolean isWarnEnabled();

45

@Override

46

public boolean isErrorEnabled();

47

@Override

48

public boolean isDebugEnabled();

49

@Override

50

public boolean isTraceEnabled();

51

52

// Status-specific methods

53

/** Add a status listener */

54

public void registerListener(StatusListener listener);

55

56

/** Remove a status listener */

57

public void removeListener(StatusListener listener);

58

59

/** Get all registered listeners */

60

public Iterable<StatusListener> getListeners();

61

62

/** Clear all listeners */

63

public void reset();

64

65

/** Get status data entries */

66

public List<StatusData> getStatusData();

67

68

/** Clear status data */

69

public void clear();

70

71

/** Set status logger level */

72

public void setLevel(Level level);

73

}

74

```

75

76

**Usage Examples:**

77

78

```java

79

public void demonstrateStatusLogger() {

80

// Get status logger instance

81

StatusLogger statusLogger = StatusLogger.getLogger();

82

83

// Status logger is used internally by Log4j, but can be accessed for diagnostics

84

statusLogger.info("Custom status message");

85

statusLogger.warn("Configuration issue detected");

86

statusLogger.error("Failed to initialize appender");

87

88

// Check status logger state

89

if (statusLogger.isDebugEnabled()) {

90

statusLogger.debug("Debug-level status information");

91

}

92

93

// Get historical status data

94

List<StatusData> statusHistory = statusLogger.getStatusData();

95

for (StatusData data : statusHistory) {

96

System.out.printf("[%s] %s - %s%n",

97

data.getLevel(),

98

new Date(data.getTimestamp()),

99

data.getMessage().getFormattedMessage());

100

}

101

102

// Clear status history

103

statusLogger.clear();

104

}

105

106

// Custom component that uses status logging

107

public class CustomAppender {

108

private static final StatusLogger STATUS_LOGGER = StatusLogger.getLogger();

109

110

public void initialize() {

111

STATUS_LOGGER.info("Initializing custom appender");

112

113

try {

114

// Initialization logic

115

setupResources();

116

STATUS_LOGGER.info("Custom appender initialized successfully");

117

} catch (Exception e) {

118

STATUS_LOGGER.error("Failed to initialize custom appender", e);

119

throw new RuntimeException("Appender initialization failed", e);

120

}

121

}

122

123

public void append(LogEvent event) {

124

try {

125

// Append logic

126

writeLogEvent(event);

127

} catch (Exception e) {

128

STATUS_LOGGER.error("Failed to append log event", e);

129

}

130

}

131

132

private void setupResources() {

133

// Resource setup

134

}

135

136

private void writeLogEvent(Object event) {

137

// Write logic

138

}

139

}

140

```

141

142

### StatusListener Interface

143

144

Interface for listening to Log4j internal status messages.

145

146

```java { .api }

147

/**

148

* Interface for listening to Log4j status messages

149

*/

150

public interface StatusListener {

151

/**

152

* Handle a status message

153

* @param data Status data containing level, message, timestamp, etc.

154

*/

155

void log(StatusData data);

156

157

/**

158

* Get the minimum level this listener wants to receive

159

* @return Minimum status level

160

*/

161

Level getStatusLevel();

162

163

/**

164

* Close/cleanup the listener

165

*/

166

void close() throws IOException;

167

}

168

```

169

170

**Usage Examples:**

171

172

```java

173

// Custom status listener implementation

174

public class CustomStatusListener implements StatusListener {

175

private final Level minimumLevel;

176

private final PrintWriter writer;

177

178

public CustomStatusListener(Level minimumLevel, String filename) throws IOException {

179

this.minimumLevel = minimumLevel;

180

this.writer = new PrintWriter(new FileWriter(filename, true));

181

}

182

183

@Override

184

public void log(StatusData data) {

185

// Only log if level is appropriate

186

if (data.getLevel().isMoreSpecificThan(minimumLevel)) {

187

writer.printf("[%s] %s [%s] %s - %s%n",

188

new Date(data.getTimestamp()),

189

data.getLevel(),

190

data.getThreadName(),

191

"StatusLogger",

192

data.getMessage().getFormattedMessage());

193

194

if (data.getThrowable() != null) {

195

data.getThrowable().printStackTrace(writer);

196

}

197

198

writer.flush();

199

}

200

}

201

202

@Override

203

public Level getStatusLevel() {

204

return minimumLevel;

205

}

206

207

@Override

208

public void close() throws IOException {

209

writer.close();

210

}

211

}

212

213

// Database status listener

214

public class DatabaseStatusListener implements StatusListener {

215

private final DataSource dataSource;

216

private final Level minimumLevel;

217

218

public DatabaseStatusListener(DataSource dataSource, Level minimumLevel) {

219

this.dataSource = dataSource;

220

this.minimumLevel = minimumLevel;

221

}

222

223

@Override

224

public void log(StatusData data) {

225

if (data.getLevel().isMoreSpecificThan(minimumLevel)) {

226

try (Connection conn = dataSource.getConnection();

227

PreparedStatement stmt = conn.prepareStatement(

228

"INSERT INTO log4j_status (timestamp, level, thread_name, message, throwable) VALUES (?, ?, ?, ?, ?)")) {

229

230

stmt.setTimestamp(1, new Timestamp(data.getTimestamp()));

231

stmt.setString(2, data.getLevel().toString());

232

stmt.setString(3, data.getThreadName());

233

stmt.setString(4, data.getMessage().getFormattedMessage());

234

235

if (data.getThrowable() != null) {

236

StringWriter sw = new StringWriter();

237

data.getThrowable().printStackTrace(new PrintWriter(sw));

238

stmt.setString(5, sw.toString());

239

} else {

240

stmt.setNull(5, Types.VARCHAR);

241

}

242

243

stmt.executeUpdate();

244

245

} catch (SQLException e) {

246

// Can't use StatusLogger here to avoid infinite recursion

247

System.err.println("Failed to log status to database: " + e.getMessage());

248

}

249

}

250

}

251

252

@Override

253

public Level getStatusLevel() {

254

return minimumLevel;

255

}

256

257

@Override

258

public void close() {

259

// Database connections are managed by DataSource

260

}

261

}

262

263

// Register and use status listeners

264

public class StatusListenerManagement {

265

266

public void setupStatusListeners() throws IOException {

267

StatusLogger statusLogger = StatusLogger.getLogger();

268

269

// File-based status listener

270

CustomStatusListener fileListener = new CustomStatusListener(Level.WARN, "log4j-status.log");

271

statusLogger.registerListener(fileListener);

272

273

// Console status listener for errors only

274

StatusListener consoleListener = new StatusListener() {

275

@Override

276

public void log(StatusData data) {

277

if (data.getLevel().isMoreSpecificThan(Level.ERROR)) {

278

System.err.printf("LOG4J ERROR: %s%n", data.getMessage().getFormattedMessage());

279

if (data.getThrowable() != null) {

280

data.getThrowable().printStackTrace(System.err);

281

}

282

}

283

}

284

285

@Override

286

public Level getStatusLevel() {

287

return Level.ERROR;

288

}

289

290

@Override

291

public void close() {

292

// Nothing to close

293

}

294

};

295

statusLogger.registerListener(consoleListener);

296

297

// Shutdown hook to clean up listeners

298

Runtime.getRuntime().addShutdownHook(new Thread(() -> {

299

try {

300

fileListener.close();

301

} catch (IOException e) {

302

System.err.println("Error closing status listener: " + e.getMessage());

303

}

304

}));

305

}

306

}

307

```

308

309

### StatusConsoleListener

310

311

Built-in status listener that outputs to console/System.err.

312

313

```java { .api }

314

/**

315

* Built-in status listener that outputs to console

316

*/

317

public class StatusConsoleListener implements StatusListener {

318

/** Create listener with default level (ERROR) */

319

public StatusConsoleListener();

320

321

/** Create listener with specific level */

322

public StatusConsoleListener(Level level);

323

324

/** Create listener with specific level and target stream */

325

public StatusConsoleListener(Level level, PrintStream stream);

326

327

@Override

328

public void log(StatusData data);

329

330

@Override

331

public Level getStatusLevel();

332

333

@Override

334

public void close();

335

336

/** Set the target print stream */

337

public void setTarget(PrintStream target);

338

339

/** Get the target print stream */

340

public PrintStream getTarget();

341

}

342

```

343

344

**Usage Examples:**

345

346

```java

347

public void demonstrateStatusConsoleListener() {

348

StatusLogger statusLogger = StatusLogger.getLogger();

349

350

// Default console listener (ERROR level to System.err)

351

StatusConsoleListener defaultConsole = new StatusConsoleListener();

352

statusLogger.registerListener(defaultConsole);

353

354

// Console listener with custom level

355

StatusConsoleListener warnConsole = new StatusConsoleListener(Level.WARN);

356

statusLogger.registerListener(warnConsole);

357

358

// Console listener with custom stream

359

StatusConsoleListener customConsole = new StatusConsoleListener(Level.INFO, System.out);

360

statusLogger.registerListener(customConsole);

361

362

// Configure listener dynamically

363

customConsole.setTarget(System.err);

364

365

// Test status logging

366

statusLogger.info("This will appear on custom console listener");

367

statusLogger.warn("This will appear on both warn and default listeners");

368

statusLogger.error("This will appear on all listeners");

369

}

370

371

// Application startup with status console listener

372

public class ApplicationStartup {

373

374

public static void main(String[] args) {

375

// Set up status console listener early in application startup

376

StatusLogger statusLogger = StatusLogger.getLogger();

377

StatusConsoleListener consoleListener = new StatusConsoleListener(Level.WARN);

378

statusLogger.registerListener(consoleListener);

379

380

// Now any Log4j initialization issues will be visible

381

Logger appLogger = LogManager.getLogger(ApplicationStartup.class);

382

appLogger.info("Application starting...");

383

384

// Application logic...

385

}

386

}

387

```

388

389

### StatusData Interface

390

391

Interface representing individual status message data.

392

393

```java { .api }

394

/**

395

* Interface representing status message data

396

*/

397

public interface StatusData {

398

/** Get the timestamp when status was created */

399

long getTimestamp();

400

401

/** Get the status level */

402

Level getLevel();

403

404

/** Get the status message */

405

Message getMessage();

406

407

/** Get the thread name where status was created */

408

String getThreadName();

409

410

/** Get associated throwable if any */

411

Throwable getThrowable();

412

413

/** Get stack trace element where status was created */

414

StackTraceElement getStackTraceElement();

415

}

416

```

417

418

**Usage Examples:**

419

420

```java

421

public void demonstrateStatusData() {

422

StatusLogger statusLogger = StatusLogger.getLogger();

423

424

// Create a custom status listener to examine StatusData

425

StatusListener dataExaminer = new StatusListener() {

426

@Override

427

public void log(StatusData data) {

428

// Examine all aspects of status data

429

System.out.println("=== Status Data Analysis ===");

430

System.out.println("Timestamp: " + new Date(data.getTimestamp()));

431

System.out.println("Level: " + data.getLevel());

432

System.out.println("Thread: " + data.getThreadName());

433

System.out.println("Message: " + data.getMessage().getFormattedMessage());

434

435

if (data.getThrowable() != null) {

436

System.out.println("Exception: " + data.getThrowable().getClass().getSimpleName());

437

System.out.println("Exception Message: " + data.getThrowable().getMessage());

438

}

439

440

if (data.getStackTraceElement() != null) {

441

StackTraceElement ste = data.getStackTraceElement();

442

System.out.printf("Location: %s.%s(%s:%d)%n",

443

ste.getClassName(),

444

ste.getMethodName(),

445

ste.getFileName(),

446

ste.getLineNumber());

447

}

448

System.out.println("========================");

449

}

450

451

@Override

452

public Level getStatusLevel() {

453

return Level.DEBUG;

454

}

455

456

@Override

457

public void close() {

458

// Nothing to close

459

}

460

};

461

462

statusLogger.registerListener(dataExaminer);

463

464

// Generate some status messages to examine

465

statusLogger.info("Status info message");

466

statusLogger.warn("Status warning message");

467

statusLogger.error("Status error message", new RuntimeException("test exception"));

468

}

469

470

// Status data aggregator

471

public class StatusDataAggregator implements StatusListener {

472

private final Map<Level, AtomicInteger> levelCounts = new ConcurrentHashMap<>();

473

private final Map<String, AtomicInteger> threadCounts = new ConcurrentHashMap<>();

474

private final AtomicLong totalMessages = new AtomicLong();

475

476

@Override

477

public void log(StatusData data) {

478

totalMessages.incrementAndGet();

479

480

// Count by level

481

levelCounts.computeIfAbsent(data.getLevel(), k -> new AtomicInteger()).incrementAndGet();

482

483

// Count by thread

484

threadCounts.computeIfAbsent(data.getThreadName(), k -> new AtomicInteger()).incrementAndGet();

485

}

486

487

@Override

488

public Level getStatusLevel() {

489

return Level.TRACE; // Capture all levels

490

}

491

492

@Override

493

public void close() {

494

// Print summary

495

System.out.println("=== Status Data Summary ===");

496

System.out.println("Total Messages: " + totalMessages.get());

497

498

System.out.println("By Level:");

499

levelCounts.forEach((level, count) ->

500

System.out.println(" " + level + ": " + count.get()));

501

502

System.out.println("By Thread:");

503

threadCounts.forEach((thread, count) ->

504

System.out.println(" " + thread + ": " + count.get()));

505

}

506

507

public Map<Level, Integer> getLevelCounts() {

508

return levelCounts.entrySet().stream()

509

.collect(Collectors.toMap(

510

Map.Entry::getKey,

511

e -> e.getValue().get()));

512

}

513

514

public Map<String, Integer> getThreadCounts() {

515

return threadCounts.entrySet().stream()

516

.collect(Collectors.toMap(

517

Map.Entry::getKey,

518

e -> e.getValue().get()));

519

}

520

}

521

```

522

523

### Common Status Scenarios

524

525

Typical status messages and how to handle them for troubleshooting.

526

527

```java { .api }

528

// Common status scenarios and troubleshooting

529

public class StatusTroubleshooting {

530

private static final StatusLogger STATUS_LOGGER = StatusLogger.getLogger();

531

532

// Configuration file not found

533

public void handleConfigurationIssues() {

534

STATUS_LOGGER.error("Configuration file not found: {}", "log4j2.xml");

535

STATUS_LOGGER.warn("Using default configuration");

536

537

// Appender initialization failure

538

STATUS_LOGGER.error("Failed to initialize FileAppender", new IOException("Permission denied"));

539

540

// Plugin loading issues

541

STATUS_LOGGER.warn("Plugin class not found: {}", "com.example.CustomPlugin");

542

}

543

}

544

```

545

546

**Usage Examples:**

547

548

```java

549

// Comprehensive status monitoring setup

550

public class StatusMonitoringSetup {

551

552

public static void setupComprehensiveStatusMonitoring() {

553

StatusLogger statusLogger = StatusLogger.getLogger();

554

555

// Set status logger to capture all levels

556

statusLogger.setLevel(Level.TRACE);

557

558

// Multi-target status listener

559

StatusListener multiListener = new StatusListener() {

560

private final List<StatusListener> listeners = Arrays.asList(

561

new StatusConsoleListener(Level.ERROR, System.err),

562

createFileListener(),

563

createMetricsListener()

564

);

565

566

@Override

567

public void log(StatusData data) {

568

listeners.forEach(listener -> {

569

try {

570

if (data.getLevel().isMoreSpecificThan(listener.getStatusLevel())) {

571

listener.log(data);

572

}

573

} catch (Exception e) {

574

System.err.println("Error in status listener: " + e.getMessage());

575

}

576

});

577

}

578

579

@Override

580

public Level getStatusLevel() {

581

return Level.TRACE; // Accept all levels

582

}

583

584

@Override

585

public void close() throws IOException {

586

for (StatusListener listener : listeners) {

587

try {

588

listener.close();

589

} catch (IOException e) {

590

System.err.println("Error closing status listener: " + e.getMessage());

591

}

592

}

593

}

594

};

595

596

statusLogger.registerListener(multiListener);

597

598

// Shutdown hook for cleanup

599

Runtime.getRuntime().addShutdownHook(new Thread(() -> {

600

try {

601

multiListener.close();

602

} catch (IOException e) {

603

System.err.println("Error during status listener cleanup: " + e.getMessage());

604

}

605

}));

606

}

607

608

private static StatusListener createFileListener() {

609

try {

610

return new CustomStatusListener(Level.WARN, "log4j-status.log");

611

} catch (IOException e) {

612

System.err.println("Failed to create file status listener: " + e.getMessage());

613

return new StatusConsoleListener(Level.WARN);

614

}

615

}

616

617

private static StatusListener createMetricsListener() {

618

return new StatusDataAggregator();

619

}

620

}

621

622

// Application with proper status monitoring

623

public class MonitoredApplication {

624

625

public static void main(String[] args) {

626

// Set up status monitoring before any Log4j usage

627

StatusMonitoringSetup.setupComprehensiveStatusMonitoring();

628

629

// Now initialize logging - any issues will be captured

630

Logger logger = LogManager.getLogger(MonitoredApplication.class);

631

632

logger.info("Application started with comprehensive status monitoring");

633

634

// Application logic...

635

636

// Check status at the end

637

StatusLogger.getLogger().getStatusData().forEach(data -> {

638

if (data.getLevel().isMoreSpecificThan(Level.WARN)) {

639

System.out.println("Warning/Error during execution: " +

640

data.getMessage().getFormattedMessage());

641

}

642

});

643

}

644

}

645

```