or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appenders.mdasync-logging.mdconfiguration.mdcore-context.mdfilters.mdindex.mdlayouts.mdlookups.mdplugins.md

plugins.mddocs/

0

# Plugin System

1

2

Log4j Core provides an extensible plugin architecture that allows custom appenders, layouts, filters, and other components to be seamlessly integrated into the logging framework. The plugin system uses annotation-based registration and factory methods for component creation.

3

4

## Capabilities

5

6

### Plugin Annotations

7

8

Core annotations for creating plugins that integrate with Log4j Core.

9

10

#### @Plugin

11

12

```java { .api }

13

/**

14

* Marks a class as a Log4j plugin

15

*/

16

@Retention(RetentionPolicy.RUNTIME)

17

@Target(ElementType.TYPE)

18

public @interface Plugin {

19

/**

20

* Plugin name used in configuration

21

* @return Plugin name

22

*/

23

String name();

24

25

/**

26

* Plugin category (e.g., "Core", "Lookup", "Converter")

27

* @return Plugin category

28

*/

29

String category();

30

31

/**

32

* Element type for configuration (e.g., "appender", "layout", "filter")

33

* @return Element type

34

*/

35

String elementType() default "";

36

37

/**

38

* Whether to print object representation

39

* @return Print object flag

40

*/

41

boolean printObject() default false;

42

43

/**

44

* Whether to defer children processing

45

* @return Defer children flag

46

*/

47

boolean deferChildren() default false;

48

}

49

```

50

51

#### @PluginFactory

52

53

```java { .api }

54

/**

55

* Marks a static method as the factory method for creating plugin instances

56

*/

57

@Retention(RetentionPolicy.RUNTIME)

58

@Target(ElementType.METHOD)

59

public @interface PluginFactory {

60

// No attributes - just marks the factory method

61

}

62

```

63

64

#### @PluginAttribute

65

66

```java { .api }

67

/**

68

* Marks a parameter as receiving an attribute value from configuration

69

*/

70

@Retention(RetentionPolicy.RUNTIME)

71

@Target(ElementType.PARAMETER)

72

public @interface PluginAttribute {

73

/**

74

* Attribute name in configuration

75

* @return Attribute name (defaults to parameter name)

76

*/

77

String value() default "";

78

79

/**

80

* Default value if attribute not specified

81

* @return Default value

82

*/

83

String defaultValue() default "";

84

85

/**

86

* Whether this attribute contains sensitive information

87

* @return Sensitive flag

88

*/

89

boolean sensitive() default false;

90

}

91

```

92

93

#### @PluginElement

94

95

```java { .api }

96

/**

97

* Marks a parameter as receiving a child element from configuration

98

*/

99

@Retention(RetentionPolicy.RUNTIME)

100

@Target(ElementType.PARAMETER)

101

public @interface PluginElement {

102

/**

103

* Element name in configuration

104

* @return Element name (defaults to parameter name)

105

*/

106

String value() default "";

107

}

108

```

109

110

#### @PluginConfiguration

111

112

```java { .api }

113

/**

114

* Marks a parameter to receive the current Configuration instance

115

*/

116

@Retention(RetentionPolicy.RUNTIME)

117

@Target(ElementType.PARAMETER)

118

public @interface PluginConfiguration {

119

// No attributes - injects current configuration

120

}

121

```

122

123

#### @PluginNode

124

125

```java { .api }

126

/**

127

* Marks a parameter to receive the configuration Node

128

*/

129

@Retention(RetentionPolicy.RUNTIME)

130

@Target(ElementType.PARAMETER)

131

public @interface PluginNode {

132

// No attributes - injects configuration node

133

}

134

```

135

136

#### @PluginLoggerContext

137

138

```java { .api }

139

/**

140

* Marks a parameter to receive the LoggerContext instance

141

*/

142

@Retention(RetentionPolicy.RUNTIME)

143

@Target(ElementType.PARAMETER)

144

public @interface PluginLoggerContext {

145

// No attributes - injects logger context

146

}

147

```

148

149

### Plugin Utilities

150

151

Utility classes for plugin management and discovery.

152

153

#### PluginManager

154

155

```java { .api }

156

/**

157

* Manager for plugin discovery and instantiation

158

*/

159

public class PluginManager {

160

/**

161

* Create PluginManager for specific category

162

* @param category Plugin category to manage

163

*/

164

public PluginManager(String category);

165

166

/**

167

* Get plugin type by name

168

* @param name Plugin name

169

* @return PluginType instance or null

170

*/

171

public PluginType<?> getPluginType(String name);

172

173

/**

174

* Get all plugin types in this category

175

* @return Map of plugin names to types

176

*/

177

public Map<String, PluginType<?>> getPlugins();

178

179

/**

180

* Create plugin instance

181

* @param name Plugin name

182

* @param elementType Expected element type

183

* @param node Configuration node

184

* @param configuration Current configuration

185

* @return Plugin instance or null

186

*/

187

public Object createPluginObject(String name, String elementType, Node node, Configuration configuration);

188

}

189

```

190

191

#### PluginType

192

193

```java { .api }

194

/**

195

* Represents a plugin type with metadata

196

* @param <T> Plugin class type

197

*/

198

public class PluginType<T> {

199

/**

200

* Get plugin class

201

* @return Plugin class

202

*/

203

public Class<T> getPluginClass();

204

205

/**

206

* Get plugin name

207

* @return Plugin name

208

*/

209

public String getKey();

210

211

/**

212

* Get element type

213

* @return Element type

214

*/

215

public String getElementType();

216

217

/**

218

* Get plugin category

219

* @return Plugin category

220

*/

221

public String getCategory();

222

223

/**

224

* Check if object should be printed

225

* @return Print object flag

226

*/

227

public boolean isObjectPrintable();

228

229

/**

230

* Check if children should be deferred

231

* @return Defer children flag

232

*/

233

public boolean isDeferChildren();

234

}

235

```

236

237

## Creating Custom Plugins

238

239

### Custom Appender Example

240

241

```java { .api }

242

/**

243

* Example custom appender plugin

244

*/

245

@Plugin(name = "MyCustom", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)

246

public class MyCustomAppender extends AbstractAppender {

247

248

/**

249

* Private constructor - use factory method

250

*/

251

private MyCustomAppender(String name, Filter filter, Layout<? extends Serializable> layout,

252

boolean ignoreExceptions, String customAttribute) {

253

super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY);

254

// Initialize custom appender

255

}

256

257

/**

258

* Append log event to custom destination

259

* @param event LogEvent to append

260

*/

261

@Override

262

public void append(LogEvent event) {

263

// Custom append logic

264

byte[] data = getLayout().toByteArray(event);

265

// Write data to custom destination

266

}

267

268

/**

269

* Factory method for creating appender instances

270

* @param name Appender name from configuration

271

* @param layout Layout component from configuration

272

* @param filter Filter component from configuration

273

* @param customAttribute Custom attribute value

274

* @param ignoreExceptions Whether to ignore exceptions

275

* @param configuration Current configuration

276

* @return MyCustomAppender instance

277

*/

278

@PluginFactory

279

public static MyCustomAppender createAppender(

280

@PluginAttribute("name") String name,

281

@PluginElement("Layout") Layout<? extends Serializable> layout,

282

@PluginElement("Filter") Filter filter,

283

@PluginAttribute("customAttribute") String customAttribute,

284

@PluginAttribute(value = "ignoreExceptions", defaultValue = "true") boolean ignoreExceptions,

285

@PluginConfiguration Configuration configuration) {

286

287

if (name == null) {

288

LOGGER.error("No name provided for MyCustomAppender");

289

return null;

290

}

291

292

if (layout == null) {

293

layout = PatternLayout.createDefaultLayout();

294

}

295

296

return new MyCustomAppender(name, filter, layout, ignoreExceptions, customAttribute);

297

}

298

}

299

```

300

301

### Custom Layout Example

302

303

```java { .api }

304

/**

305

* Example custom layout plugin

306

*/

307

@Plugin(name = "MyCustomLayout", category = Core.CATEGORY_NAME, elementType = Layout.ELEMENT_TYPE)

308

public class MyCustomLayout extends AbstractStringLayout {

309

310

private final String prefix;

311

private final String suffix;

312

313

/**

314

* Private constructor - use factory method

315

*/

316

private MyCustomLayout(Charset charset, String prefix, String suffix) {

317

super(charset);

318

this.prefix = prefix != null ? prefix : "";

319

this.suffix = suffix != null ? suffix : "";

320

}

321

322

/**

323

* Format log event to string

324

* @param event LogEvent to format

325

* @return Formatted string

326

*/

327

@Override

328

public String toSerializable(LogEvent event) {

329

StringBuilder sb = new StringBuilder();

330

sb.append(prefix);

331

sb.append(event.getTimeMillis()).append(" | ");

332

sb.append(event.getLevel()).append(" | ");

333

sb.append(event.getLoggerName()).append(" | ");

334

sb.append(event.getMessage().getFormattedMessage());

335

sb.append(suffix);

336

sb.append(System.lineSeparator());

337

return sb.toString();

338

}

339

340

/**

341

* Factory method for creating layout instances

342

* @param charset Character encoding

343

* @param prefix Prefix string for each log entry

344

* @param suffix Suffix string for each log entry

345

* @return MyCustomLayout instance

346

*/

347

@PluginFactory

348

public static MyCustomLayout createLayout(

349

@PluginAttribute(value = "charset", defaultValue = "UTF-8") Charset charset,

350

@PluginAttribute("prefix") String prefix,

351

@PluginAttribute("suffix") String suffix) {

352

353

return new MyCustomLayout(charset, prefix, suffix);

354

}

355

}

356

```

357

358

### Custom Filter Example

359

360

```java { .api }

361

/**

362

* Example custom filter plugin

363

*/

364

@Plugin(name = "MyCustomFilter", category = Core.CATEGORY_NAME, elementType = Filter.ELEMENT_TYPE)

365

public class MyCustomFilter extends AbstractFilter {

366

367

private final String requiredProperty;

368

369

/**

370

* Private constructor - use factory method

371

*/

372

private MyCustomFilter(String requiredProperty, Result onMatch, Result onMismatch) {

373

super(onMatch, onMismatch);

374

this.requiredProperty = requiredProperty;

375

}

376

377

/**

378

* Filter log event based on custom criteria

379

* @param event LogEvent to filter

380

* @return Filter result

381

*/

382

@Override

383

public Result filter(LogEvent event) {

384

// Custom filtering logic

385

String propertyValue = event.getContextData().getValue(requiredProperty);

386

if (propertyValue != null && !propertyValue.isEmpty()) {

387

return onMatch;

388

}

389

return onMismatch;

390

}

391

392

/**

393

* Factory method for creating filter instances

394

* @param requiredProperty Property that must be present

395

* @param match Result when filter matches

396

* @param mismatch Result when filter doesn't match

397

* @return MyCustomFilter instance

398

*/

399

@PluginFactory

400

public static MyCustomFilter createFilter(

401

@PluginAttribute("requiredProperty") String requiredProperty,

402

@PluginAttribute(value = "onMatch", defaultValue = "NEUTRAL") Result match,

403

@PluginAttribute(value = "onMismatch", defaultValue = "DENY") Result mismatch) {

404

405

if (requiredProperty == null) {

406

LOGGER.error("requiredProperty is required for MyCustomFilter");

407

return null;

408

}

409

410

return new MyCustomFilter(requiredProperty, match, mismatch);

411

}

412

}

413

```

414

415

### Custom Lookup Example

416

417

```java { .api }

418

/**

419

* Example custom lookup plugin for variable substitution

420

*/

421

@Plugin(name = "mycustom", category = StrLookup.CATEGORY)

422

public class MyCustomLookup implements StrLookup {

423

424

private static final Map<String, String> customData = new HashMap<>();

425

426

static {

427

customData.put("appname", "MyApplication");

428

customData.put("version", "1.0.0");

429

customData.put("environment", "production");

430

}

431

432

/**

433

* Look up value by key

434

* @param key Lookup key

435

* @return Value for key or null

436

*/

437

@Override

438

public String lookup(String key) {

439

return customData.get(key);

440

}

441

442

/**

443

* Look up value with LogEvent context

444

* @param event LogEvent for context

445

* @param key Lookup key

446

* @return Value for key or null

447

*/

448

@Override

449

public String lookup(LogEvent event, String key) {

450

// Can use log event for context-specific lookups

451

return lookup(key);

452

}

453

454

/**

455

* Factory method for creating lookup instances

456

* @return MyCustomLookup instance

457

*/

458

@PluginFactory

459

public static MyCustomLookup createLookup() {

460

return new MyCustomLookup();

461

}

462

}

463

```

464

465

## Plugin Configuration Usage

466

467

Once plugins are created, they can be used in configuration files:

468

469

### XML Configuration

470

```xml

471

<Configuration status="WARN" packages="com.example.plugins">

472

<Appenders>

473

<MyCustom name="Custom" customAttribute="value">

474

<MyCustomLayout prefix="[CUSTOM] " suffix=" [END]"/>

475

<MyCustomFilter requiredProperty="userId" onMatch="ACCEPT" onMismatch="DENY"/>

476

</MyCustom>

477

</Appenders>

478

<Loggers>

479

<Root level="INFO">

480

<AppenderRef ref="Custom"/>

481

</Root>

482

</Loggers>

483

</Configuration>

484

```

485

486

### Using Custom Lookup

487

```xml

488

<Configuration status="WARN">

489

<Properties>

490

<Property name="filename">logs/${mycustom:appname}-${mycustom:environment}.log</Property>

491

</Properties>

492

<Appenders>

493

<File name="File" fileName="${filename}">

494

<PatternLayout pattern="%d %level %logger - %msg%n"/>

495

</File>

496

</Appenders>

497

</Configuration>

498

```

499

500

## Plugin Discovery and Loading

501

502

### Automatic Discovery

503

Log4j automatically discovers plugins in:

504

- `org.apache.logging.log4j.core` package (built-in plugins)

505

- Packages specified in `packages` attribute of Configuration

506

- Packages specified via system property `log4j2.packages`

507

508

### Manual Plugin Loading

509

```java

510

// Programmatically add plugin packages

511

System.setProperty("log4j2.packages", "com.example.plugins,com.mycompany.logging");

512

513

// Or in configuration

514

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

515

builder.setPackages("com.example.plugins");

516

```

517

518

## Plugin Categories

519

520

Standard plugin categories in Log4j Core:

521

522

- **"Core"**: Appenders, layouts, filters, lookups

523

- **"Converter"**: Pattern layout converters

524

- **"Lookup"**: Variable lookup providers

525

- **"TypeConverter"**: Type conversion plugins

526

- **"ConfigurationFactory"**: Configuration file parsers