or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appenders.mdbuilders.mdconfiguration.mdcontext.mdindex.mdlayouts.mdlogging.mdspi.md

spi.mddocs/

0

# SPI and Extension Points

1

2

The Service Provider Interface (SPI) classes provide extension points for custom functionality including LoggerRepository, ErrorHandler, Filter, and other pluggable components for advanced logging system customization.

3

4

## Core SPI Interfaces

5

6

### LoggerRepository Interface

7

8

```java { .api }

9

public interface LoggerRepository {

10

// Logger management

11

Logger getLogger(String name);

12

Logger getLogger(String name, LoggerFactory factory);

13

Logger getRootLogger();

14

Logger exists(String name);

15

16

// Repository state

17

Enumeration getCurrentLoggers();

18

Enumeration getCurrentCategories();

19

20

// Configuration

21

void shutdown();

22

void resetConfiguration();

23

boolean isDisabled(int level);

24

void setThreshold(Level level);

25

void setThreshold(String val);

26

Level getThreshold();

27

28

// Error handling

29

void emitNoAppenderWarning(Category cat);

30

31

// Hierarchy management

32

void setLoggerFactory(LoggerFactory factory);

33

LoggerFactory getLoggerFactory();

34

}

35

```

36

37

**Parameters:**

38

- `name` - String logger name

39

- `factory` - LoggerFactory for logger creation

40

- `level` - Integer level to check or Level to set

41

- `val` - String threshold value

42

- `cat` - Category for warning

43

44

**Returns:**

45

- `Logger` instances

46

- `Enumeration` of loggers/categories

47

- `boolean` for disabled checks

48

- `Level` current threshold

49

- `LoggerFactory` current factory

50

51

### LoggerFactory Interface

52

53

```java { .api }

54

public interface LoggerFactory {

55

// Create logger instance

56

Logger makeNewLoggerInstance(String name);

57

}

58

```

59

60

**Parameters:**

61

- `name` - String name for the new logger

62

63

**Returns:**

64

- `Logger` newly created logger instance

65

66

### ErrorHandler Interface

67

68

```java { .api }

69

public interface ErrorHandler {

70

// Error handling methods

71

void error(String message);

72

void error(String message, Exception ex, int errorCode);

73

void error(String message, Exception ex, int errorCode, LoggingEvent event);

74

75

// Appender association

76

void setAppender(Appender appender);

77

void setBackupAppender(Appender appender);

78

void setLogger(Logger logger);

79

80

// Activation

81

void activateOptions();

82

}

83

```

84

85

**Parameters:**

86

- `message` - String error message

87

- `ex` - Exception that occurred

88

- `errorCode` - Integer error code

89

- `event` - LoggingEvent being processed

90

- `appender` - Appender for association

91

- `logger` - Logger for association

92

93

### Filter Interface

94

95

```java { .api }

96

public interface Filter {

97

// Filter results

98

int DENY = -1;

99

int NEUTRAL = 0;

100

int ACCEPT = 1;

101

102

// Decision method

103

int decide(LoggingEvent event);

104

105

// Filter chaining

106

Filter getNext();

107

void setNext(Filter next);

108

}

109

```

110

111

**Parameters:**

112

- `event` - LoggingEvent to evaluate

113

- `next` - Filter next filter in chain

114

115

**Returns:**

116

- `int` decision (DENY, NEUTRAL, or ACCEPT)

117

- `Filter` next filter in chain

118

119

## Logger SPI Classes

120

121

### DefaultCategoryFactory

122

123

```java { .api }

124

public class DefaultCategoryFactory implements LoggerFactory {

125

// Constructor

126

public DefaultCategoryFactory();

127

128

// Factory method implementation

129

@Override

130

public Logger makeNewLoggerInstance(String name);

131

}

132

```

133

134

**Parameters:**

135

- `name` - String logger name

136

137

**Returns:**

138

- `Logger` new logger instance

139

140

### Hierarchy

141

142

```java { .api }

143

public class Hierarchy implements LoggerRepository {

144

// Constructor

145

public Hierarchy(Logger root);

146

147

// Logger operations

148

@Override

149

public Logger getLogger(String name);

150

@Override

151

public Logger getLogger(String name, LoggerFactory factory);

152

@Override

153

public Logger getRootLogger();

154

@Override

155

public Logger exists(String name);

156

157

// Enumeration

158

@Override

159

public Enumeration getCurrentLoggers();

160

@Override

161

public Enumeration getCurrentCategories();

162

163

// Configuration

164

@Override

165

public void shutdown();

166

@Override

167

public void resetConfiguration();

168

@Override

169

public boolean isDisabled(int level);

170

@Override

171

public void setThreshold(Level level);

172

@Override

173

public Level getThreshold();

174

175

// Factory management

176

@Override

177

public void setLoggerFactory(LoggerFactory factory);

178

@Override

179

public LoggerFactory getLoggerFactory();

180

181

// Hierarchy-specific methods

182

public void clear();

183

public void overrideAsNeeded(String override);

184

}

185

```

186

187

**Parameters:**

188

- `root` - Logger root logger for hierarchy

189

- `name` - String logger name

190

- `factory` - LoggerFactory for logger creation

191

- `level` - Level or integer threshold

192

- `override` - String override configuration

193

194

**Returns:**

195

- `Logger`, `Enumeration`, `Level`, `LoggerFactory` as appropriate

196

- `boolean` for threshold checks

197

198

## Error Handler Implementations

199

200

### OnlyOnceErrorHandler

201

202

```java { .api }

203

public class OnlyOnceErrorHandler implements ErrorHandler {

204

// Constants

205

public static final String WARN_PREFIX = "log4j warning: ";

206

public static final String ERROR_PREFIX = "log4j error: ";

207

208

// Constructor

209

public OnlyOnceErrorHandler();

210

211

// Error handling

212

@Override

213

public void error(String message);

214

@Override

215

public void error(String message, Exception ex, int errorCode);

216

@Override

217

public void error(String message, Exception ex, int errorCode, LoggingEvent event);

218

219

// Configuration

220

@Override

221

public void setAppender(Appender appender);

222

@Override

223

public void setBackupAppender(Appender appender);

224

@Override

225

public void setLogger(Logger logger);

226

@Override

227

public void activateOptions();

228

}

229

```

230

231

**Parameters:**

232

- `message` - String error message

233

- `ex` - Exception that occurred

234

- `errorCode` - Integer error code

235

- `event` - LoggingEvent being processed

236

- `appender` - Appender for configuration

237

- `logger` - Logger for configuration

238

239

## Filter Implementations

240

241

### LevelRangeFilter

242

243

```java { .api }

244

public class LevelRangeFilter implements Filter {

245

// Configuration

246

public void setLevelMin(Level levelMin);

247

public Level getLevelMin();

248

public void setLevelMax(Level levelMax);

249

public Level getLevelMax();

250

public void setAcceptOnMatch(boolean acceptOnMatch);

251

public boolean getAcceptOnMatch();

252

253

// Filter implementation

254

@Override

255

public int decide(LoggingEvent event);

256

@Override

257

public Filter getNext();

258

@Override

259

public void setNext(Filter next);

260

261

// Lifecycle

262

public void activateOptions();

263

}

264

```

265

266

**Parameters:**

267

- `levelMin` - Level minimum level in range

268

- `levelMax` - Level maximum level in range

269

- `acceptOnMatch` - Boolean accept or deny on match

270

- `event` - LoggingEvent to evaluate

271

- `next` - Filter next filter in chain

272

273

**Returns:**

274

- `Level` min/max levels

275

- `boolean` accept on match setting

276

- `int` filter decision

277

- `Filter` next filter

278

279

### LevelMatchFilter

280

281

```java { .api }

282

public class LevelMatchFilter implements Filter {

283

// Configuration

284

public void setLevel(Level level);

285

public Level getLevel();

286

public void setAcceptOnMatch(boolean acceptOnMatch);

287

public boolean getAcceptOnMatch();

288

289

// Filter implementation

290

@Override

291

public int decide(LoggingEvent event);

292

@Override

293

public Filter getNext();

294

@Override

295

public void setNext(Filter next);

296

297

// Lifecycle

298

public void activateOptions();

299

}

300

```

301

302

**Parameters:**

303

- `level` - Level to match against

304

- `acceptOnMatch` - Boolean accept or deny on match

305

- `event` - LoggingEvent to evaluate

306

- `next` - Filter next filter in chain

307

308

**Returns:**

309

- `Level` match level

310

- `boolean` accept on match setting

311

- `int` filter decision

312

- `Filter` next filter

313

314

### StringMatchFilter

315

316

```java { .api }

317

public class StringMatchFilter implements Filter {

318

// Configuration

319

public void setStringToMatch(String s);

320

public String getStringToMatch();

321

public void setAcceptOnMatch(boolean acceptOnMatch);

322

public boolean getAcceptOnMatch();

323

324

// Filter implementation

325

@Override

326

public int decide(LoggingEvent event);

327

@Override

328

public Filter getNext();

329

@Override

330

public void setNext(Filter next);

331

332

// Lifecycle

333

public void activateOptions();

334

}

335

```

336

337

**Parameters:**

338

- `s` - String to match in log messages

339

- `acceptOnMatch` - Boolean accept or deny on match

340

- `event` - LoggingEvent to evaluate

341

- `next` - Filter next filter in chain

342

343

**Returns:**

344

- `String` match string

345

- `boolean` accept on match setting

346

- `int` filter decision

347

- `Filter` next filter

348

349

## Configuration SPI

350

351

### OptionHandler Interface

352

353

```java { .api }

354

public interface OptionHandler {

355

// Activate configured options

356

void activateOptions();

357

}

358

```

359

360

### Configurator Interface

361

362

```java { .api }

363

public interface Configurator {

364

// Configure from URL

365

void doConfigure(URL url, LoggerRepository repository);

366

367

// Configure from InputStream

368

void doConfigure(InputStream inputStream, LoggerRepository repository);

369

}

370

```

371

372

**Parameters:**

373

- `url` - URL pointing to configuration

374

- `inputStream` - InputStream containing configuration

375

- `repository` - LoggerRepository to configure

376

377

## Advanced SPI Components

378

379

### LoggingEvent

380

381

```java { .api }

382

public class LoggingEvent implements Serializable {

383

// Event properties

384

public String getLoggerName();

385

public Logger getLogger();

386

public Level getLevel();

387

public Object getMessage();

388

public String getRenderedMessage();

389

public String[] getThrowableStrRep();

390

public ThrowableInformation getThrowableInformation();

391

public long getTimeStamp();

392

public String getThreadName();

393

public LocationInfo getLocationInformation();

394

public String getFQNOfLoggerClass();

395

396

// MDC access

397

public Object getMDC(String key);

398

public void getMDCCopy();

399

400

// NDC access

401

public String getNDC();

402

403

// Properties

404

public Set getPropertyKeySet();

405

public String getProperty(String key);

406

}

407

```

408

409

**Parameters:**

410

- `key` - String key for MDC or property access

411

412

**Returns:**

413

- Various return types depending on method (String, Level, Object, etc.)

414

415

### LocationInfo

416

417

```java { .api }

418

public class LocationInfo implements Serializable {

419

// Location constants

420

public static final String NA = "?";

421

422

// Location information

423

public String getClassName();

424

public String getFileName();

425

public String getLineNumber();

426

public String getMethodName();

427

public String fullInfo();

428

}

429

```

430

431

**Returns:**

432

- `String` location information components

433

434

### ThrowableInformation

435

436

```java { .api }

437

public class ThrowableInformation implements Serializable {

438

// Constructor

439

public ThrowableInformation(Throwable throwable);

440

public ThrowableInformation(String[] rep);

441

442

// Throwable access

443

public Throwable getThrowable();

444

public String[] getThrowableStrRep();

445

}

446

```

447

448

**Parameters:**

449

- `throwable` - Throwable exception

450

- `rep` - String array representation

451

452

**Returns:**

453

- `Throwable` original exception

454

- `String[]` string representation

455

456

## Usage Examples

457

458

### Custom Logger Factory

459

```java

460

import org.apache.log4j.spi.LoggerFactory;

461

import org.apache.log4j.Logger;

462

463

public class CustomLoggerFactory implements LoggerFactory {

464

465

@Override

466

public Logger makeNewLoggerInstance(String name) {

467

// Create custom logger with enhanced functionality

468

return new CustomLogger(name);

469

}

470

471

// Custom logger implementation

472

public static class CustomLogger extends Logger {

473

public CustomLogger(String name) {

474

super(name);

475

}

476

477

// Add custom logging methods

478

public void audit(Object message) {

479

// Custom audit logging

480

super.info("AUDIT: " + message);

481

}

482

483

public void security(Object message) {

484

// Custom security logging

485

super.warn("SECURITY: " + message);

486

}

487

}

488

}

489

```

490

491

### Custom Error Handler

492

```java

493

import org.apache.log4j.spi.ErrorHandler;

494

import org.apache.log4j.spi.LoggingEvent;

495

import org.apache.log4j.*;

496

497

public class CustomErrorHandler implements ErrorHandler {

498

private Appender appender;

499

private Appender backupAppender;

500

private Logger logger;

501

502

@Override

503

public void error(String message) {

504

System.err.println("Custom Error Handler: " + message);

505

}

506

507

@Override

508

public void error(String message, Exception ex, int errorCode) {

509

System.err.println("Custom Error Handler [" + errorCode + "]: " + message);

510

if (ex != null) {

511

ex.printStackTrace();

512

}

513

}

514

515

@Override

516

public void error(String message, Exception ex, int errorCode, LoggingEvent event) {

517

error(message, ex, errorCode);

518

519

// Try backup appender if available

520

if (backupAppender != null && event != null) {

521

try {

522

backupAppender.doAppend(event);

523

} catch (Exception backupEx) {

524

System.err.println("Backup appender also failed: " + backupEx.getMessage());

525

}

526

}

527

}

528

529

@Override

530

public void setAppender(Appender appender) {

531

this.appender = appender;

532

}

533

534

@Override

535

public void setBackupAppender(Appender appender) {

536

this.backupAppender = appender;

537

}

538

539

@Override

540

public void setLogger(Logger logger) {

541

this.logger = logger;

542

}

543

544

@Override

545

public void activateOptions() {

546

// Initialize any resources

547

}

548

}

549

```

550

551

### Custom Filter Implementation

552

```java

553

import org.apache.log4j.spi.Filter;

554

import org.apache.log4j.spi.LoggingEvent;

555

556

public class CustomMessageFilter implements Filter {

557

private String[] forbiddenWords;

558

private Filter next;

559

560

public CustomMessageFilter(String[] forbiddenWords) {

561

this.forbiddenWords = forbiddenWords;

562

}

563

564

@Override

565

public int decide(LoggingEvent event) {

566

String message = event.getRenderedMessage();

567

568

if (message != null) {

569

for (String forbidden : forbiddenWords) {

570

if (message.toLowerCase().contains(forbidden.toLowerCase())) {

571

return Filter.DENY; // Block messages with forbidden words

572

}

573

}

574

}

575

576

return Filter.NEUTRAL; // Let other filters decide

577

}

578

579

@Override

580

public Filter getNext() {

581

return next;

582

}

583

584

@Override

585

public void setNext(Filter next) {

586

this.next = next;

587

}

588

589

// Usage example

590

public static void setupFilteredLogging() {

591

// Create filter to block sensitive information

592

String[] sensitiveWords = {"password", "ssn", "credit card"};

593

CustomMessageFilter filter = new CustomMessageFilter(sensitiveWords);

594

595

// Create appender with filter

596

ConsoleAppender appender = new ConsoleAppender(

597

new PatternLayout("%-5p %c - %m%n")

598

);

599

appender.addFilter(filter);

600

601

// Configure logger

602

Logger logger = Logger.getLogger("sensitive");

603

logger.addAppender(appender);

604

605

// Test filtering

606

logger.info("User login successful"); // Will appear

607

logger.info("User password is secret"); // Will be blocked

608

logger.info("Processing credit card transaction"); // Will be blocked

609

}

610

}

611

```

612

613

### Custom LoggerRepository

614

```java

615

import org.apache.log4j.spi.*;

616

import org.apache.log4j.*;

617

import java.util.*;

618

import java.util.concurrent.ConcurrentHashMap;

619

620

public class CustomLoggerRepository implements LoggerRepository {

621

private final Map<String, Logger> loggers = new ConcurrentHashMap<>();

622

private final Logger rootLogger;

623

private LoggerFactory loggerFactory = new DefaultCategoryFactory();

624

private Level threshold = Level.ALL;

625

626

public CustomLoggerRepository() {

627

this.rootLogger = new Logger("root");

628

this.rootLogger.setLevel(Level.DEBUG);

629

loggers.put("root", rootLogger);

630

}

631

632

@Override

633

public Logger getLogger(String name) {

634

return getLogger(name, loggerFactory);

635

}

636

637

@Override

638

public Logger getLogger(String name, LoggerFactory factory) {

639

Logger logger = loggers.get(name);

640

if (logger == null) {

641

logger = factory.makeNewLoggerInstance(name);

642

loggers.put(name, logger);

643

644

// Set up parent-child relationships

645

setupParentChild(logger, name);

646

}

647

return logger;

648

}

649

650

@Override

651

public Logger getRootLogger() {

652

return rootLogger;

653

}

654

655

@Override

656

public Logger exists(String name) {

657

return loggers.get(name);

658

}

659

660

@Override

661

public Enumeration getCurrentLoggers() {

662

return Collections.enumeration(

663

loggers.values().stream()

664

.filter(logger -> !logger.getName().equals("root"))

665

.collect(java.util.stream.Collectors.toList())

666

);

667

}

668

669

@Override

670

public Enumeration getCurrentCategories() {

671

return getCurrentLoggers();

672

}

673

674

@Override

675

public void shutdown() {

676

// Close all appenders

677

for (Logger logger : loggers.values()) {

678

Enumeration appenders = logger.getAllAppenders();

679

while (appenders.hasMoreElements()) {

680

Appender appender = (Appender) appenders.nextElement();

681

appender.close();

682

}

683

}

684

}

685

686

@Override

687

public void resetConfiguration() {

688

// Remove all appenders and reset levels

689

for (Logger logger : loggers.values()) {

690

logger.removeAllAppenders();

691

logger.setLevel(null);

692

}

693

rootLogger.setLevel(Level.DEBUG);

694

}

695

696

@Override

697

public boolean isDisabled(int level) {

698

return threshold.toInt() > level;

699

}

700

701

@Override

702

public void setThreshold(Level level) {

703

this.threshold = level;

704

}

705

706

@Override

707

public void setThreshold(String val) {

708

setThreshold(Level.toLevel(val));

709

}

710

711

@Override

712

public Level getThreshold() {

713

return threshold;

714

}

715

716

@Override

717

public void emitNoAppenderWarning(Category cat) {

718

System.err.println("No appenders could be found for logger (" +

719

cat.getName() + ").");

720

}

721

722

@Override

723

public void setLoggerFactory(LoggerFactory factory) {

724

this.loggerFactory = factory;

725

}

726

727

@Override

728

public LoggerFactory getLoggerFactory() {

729

return loggerFactory;

730

}

731

732

private void setupParentChild(Logger logger, String name) {

733

// Simplified parent-child setup

734

int lastDot = name.lastIndexOf('.');

735

if (lastDot > 0) {

736

String parentName = name.substring(0, lastDot);

737

Logger parent = getLogger(parentName);

738

// Set up parent relationship (simplified)

739

}

740

}

741

}

742

```

743

744

### Advanced Filter Chain

745

```java

746

import org.apache.log4j.spi.Filter;

747

import org.apache.log4j.spi.LoggingEvent;

748

import org.apache.log4j.*;

749

750

public class FilterChainExample {

751

752

public static void setupAdvancedFiltering() {

753

// Create multiple filters

754

LevelMatchFilter infoFilter = new LevelMatchFilter();

755

infoFilter.setLevel(Level.INFO);

756

infoFilter.setAcceptOnMatch(true);

757

758

LevelRangeFilter errorFilter = new LevelRangeFilter();

759

errorFilter.setLevelMin(Level.ERROR);

760

errorFilter.setLevelMax(Level.FATAL);

761

errorFilter.setAcceptOnMatch(true);

762

763

StringMatchFilter sensitiveFilter = new StringMatchFilter();

764

sensitiveFilter.setStringToMatch("password");

765

sensitiveFilter.setAcceptOnMatch(false); // Deny

766

767

// Chain filters

768

infoFilter.setNext(errorFilter);

769

errorFilter.setNext(sensitiveFilter);

770

771

// Create appender with filter chain

772

ConsoleAppender appender = new ConsoleAppender(

773

new PatternLayout("%-5p %c - %m%n")

774

);

775

appender.addFilter(infoFilter);

776

777

// Configure logger

778

Logger logger = Logger.getLogger("filtered");

779

logger.addAppender(appender);

780

logger.setLevel(Level.DEBUG);

781

782

// Test filter chain

783

logger.debug("Debug message"); // Filtered out (not INFO or ERROR+)

784

logger.info("Info message"); // Passes (INFO level)

785

logger.info("User password changed"); // Blocked (contains "password")

786

logger.error("Error occurred"); // Passes (ERROR level)

787

}

788

}

789

```

790

791

## Error Handler Implementations

792

793

### FallbackErrorHandler

794

795

An error handler that provides failover capability by switching to a backup appender when the primary appender fails.

796

797

```java { .api }

798

public class FallbackErrorHandler implements ErrorHandler {

799

// Constructors

800

public FallbackErrorHandler();

801

802

// ErrorHandler interface methods

803

public void error(String message);

804

public void error(String message, Exception e, int errorCode);

805

public void error(String message, Exception e, int errorCode, LoggingEvent event);

806

public void setAppender(Appender primary);

807

public void setBackupAppender(Appender backup);

808

public void setLogger(Logger logger);

809

810

// Activation

811

public void activateOptions();

812

}

813

```

814

815

**Parameters:**

816

- `message` - Error message describing the failure

817

- `e` - Exception that caused the error

818

- `errorCode` - Numeric error code from ErrorCode constants

819

- `event` - LoggingEvent that failed to be processed

820

- `primary` - Primary appender that failed

821

- `backup` - Backup appender to use for failover

822

- `logger` - Logger to update during failover

823

824

**Usage Example:**

825

```java

826

import org.apache.log4j.*;

827

import org.apache.log4j.varia.FallbackErrorHandler;

828

829

public class FallbackErrorHandlerExample {

830

public void setupFallback() {

831

// Create primary appender (might fail)

832

FileAppender primaryAppender = new FileAppender(

833

new PatternLayout("%d %-5p %c - %m%n"),

834

"/tmp/primary.log",

835

true

836

);

837

primaryAppender.setName("primary");

838

839

// Create backup appender (console)

840

ConsoleAppender backupAppender = new ConsoleAppender(

841

new PatternLayout("FALLBACK: %d %-5p %c - %m%n")

842

);

843

backupAppender.setName("backup");

844

845

// Create fallback error handler

846

FallbackErrorHandler errorHandler = new FallbackErrorHandler();

847

errorHandler.setAppender(primaryAppender);

848

errorHandler.setBackupAppender(backupAppender);

849

errorHandler.setLogger(Logger.getLogger("com.myapp"));

850

errorHandler.activateOptions();

851

852

// Set error handler on primary appender

853

primaryAppender.setErrorHandler(errorHandler);

854

855

// Configure logger

856

Logger logger = Logger.getLogger("com.myapp");

857

logger.addAppender(primaryAppender);

858

}

859

}

860

```

861

862

## Rewrite Policies

863

864

### RewritePolicy Interface

865

866

Base interface for implementing logging event rewrite strategies used with RewriteAppender.

867

868

```java { .api }

869

public interface RewritePolicy {

870

/**

871

* Rewrite a logging event

872

* @param source original logging event

873

* @return rewritten event, original event, or null to suppress

874

*/

875

LoggingEvent rewrite(LoggingEvent source);

876

}

877

```

878

879

### MapRewritePolicy

880

881

A rewrite policy that processes events where the message implements java.util.Map, combining message properties with the event's existing properties.

882

883

```java { .api }

884

public class MapRewritePolicy implements RewritePolicy {

885

// Constructor

886

public MapRewritePolicy();

887

888

// RewritePolicy implementation

889

public LoggingEvent rewrite(LoggingEvent source);

890

}

891

```

892

893

**Usage Example:**

894

```java

895

import org.apache.log4j.*;

896

import org.apache.log4j.rewrite.MapRewritePolicy;

897

import java.util.HashMap;

898

import java.util.Map;

899

900

public class RewritePolicyExample {

901

public void setupMapRewrite() {

902

// Create rewrite policy

903

MapRewritePolicy rewritePolicy = new MapRewritePolicy();

904

905

// Create RewriteAppender (would need to be implemented)

906

// RewriteAppender rewriteAppender = new RewriteAppender();

907

// rewriteAppender.setRewritePolicy(rewritePolicy);

908

909

// Example of map-based logging

910

Logger logger = Logger.getLogger("com.myapp");

911

912

Map<String, Object> logMap = new HashMap<>();

913

logMap.put("message", "User action performed");

914

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

915

logMap.put("action", "login");

916

logMap.put("timestamp", System.currentTimeMillis());

917

918

// Log the map - will be processed by MapRewritePolicy

919

logger.info(logMap);

920

}

921

}

922

```

923

924

## Object Renderers

925

926

### ObjectRenderer Interface

927

928

Interface for custom object-to-string conversion in log messages.

929

930

```java { .api }

931

public interface ObjectRenderer {

932

/**

933

* Render the object as a String

934

* @param o object to render

935

* @return String representation of the object

936

*/

937

String doRender(Object o);

938

}

939

```

940

941

### RendererMap

942

943

Manages mapping between classes and their corresponding ObjectRenderer implementations.

944

945

```java { .api }

946

public class RendererMap {

947

// Constructor

948

public RendererMap();

949

950

// Static methods

951

public static void addRenderer(RendererSupport repository, String renderedClassName, String renderingClassName);

952

953

// Instance methods

954

public ObjectRenderer get(Object o);

955

public ObjectRenderer get(Class clazz);

956

public void put(Class clazz, ObjectRenderer renderer);

957

public void clear();

958

}

959

```

960

961

**Parameters:**

962

- `repository` - RendererSupport instance (typically LoggerRepository)

963

- `renderedClassName` - Class name to be rendered

964

- `renderingClassName` - ObjectRenderer implementation class name

965

- `o` - Object instance to find renderer for

966

- `clazz` - Class to find renderer for

967

- `renderer` - ObjectRenderer to associate with class

968

969

**Returns:**

970

- `get()` methods return ObjectRenderer instance or default renderer

971

- `put()` and `clear()` methods return void

972

973

**Usage Example:**

974

```java

975

import org.apache.log4j.*;

976

import org.apache.log4j.or.ObjectRenderer;

977

import org.apache.log4j.or.RendererMap;

978

979

public class ObjectRendererExample {

980

981

// Custom renderer for User objects

982

public static class UserRenderer implements ObjectRenderer {

983

public String doRender(Object o) {

984

if (o instanceof User) {

985

User user = (User) o;

986

return "User[id=" + user.getId() + ", name=" + user.getName() + "]";

987

}

988

return o.toString();

989

}

990

}

991

992

public void setupCustomRenderer() {

993

// Get logger repository that supports renderers

994

LoggerRepository repository = LogManager.getLoggerRepository();

995

996

// Add custom renderer for User class

997

RendererMap.addRenderer(

998

(org.apache.log4j.spi.RendererSupport) repository,

999

"com.myapp.User",

1000

"com.myapp.UserRenderer"

1001

);

1002

1003

// Now User objects will be rendered using UserRenderer

1004

Logger logger = Logger.getLogger("com.myapp");

1005

User user = new User(123, "John Doe");

1006

logger.info("Created user: " + user); // Uses custom renderer

1007

}

1008

}

1009

```

1010

1011

## JMX Support (Deprecated)

1012

1013

Log4j 1.x compatibility API includes deprecated JMX management classes for backward compatibility. These classes are primarily for legacy applications and new code should use Log4j 2.x JMX features directly.

1014

1015

### Key JMX Classes

1016

1017

```java { .api }

1018

// Main JMX agent (deprecated)

1019

@Deprecated

1020

public class Agent {

1021

public static Object createServer(int port);

1022

public static void start(Object server);

1023

}

1024

1025

// MBean implementations (deprecated)

1026

@Deprecated

1027

public class HierarchyDynamicMBean extends AbstractDynamicMBean;

1028

1029

@Deprecated

1030

public class LoggerDynamicMBean extends AbstractDynamicMBean;

1031

1032

@Deprecated

1033

public class AppenderDynamicMBean extends AbstractDynamicMBean;

1034

```

1035

1036

**Note:** These JMX classes are deprecated and maintained only for compatibility. For new applications, use Log4j 2.x's built-in JMX support instead.