or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appenders.mdconfiguration.mdencoders-layouts.mdfilters-evaluators.mdindex.mdmodel-framework.mdnetwork-logging.mdpatterns.mdrolling-policies.mdutilities.md

encoders-layouts.mddocs/

0

# Encoders and Layouts

1

2

Event encoding and transformation system for converting log events into formatted byte arrays or strings. Encoders are the modern approach for formatting log output, while layouts provide the traditional string-based formatting interface.

3

4

## Capabilities

5

6

### Encoder Interface

7

8

The primary interface for transforming log events into byte arrays, supporting headers, footers, and character encoding.

9

10

```java { .api }

11

/**

12

* Interface for transforming events into byte arrays.

13

* Encoders are the recommended approach for formatting log output.

14

*/

15

public interface Encoder<E> extends ContextAware, LifeCycle {

16

/**

17

* Get header bytes to write at the beginning of the output.

18

* @return header bytes, or null if no header

19

*/

20

byte[] headerBytes();

21

22

/**

23

* Encode a single event into a byte array.

24

* @param event the event to encode

25

* @return encoded bytes for the event

26

*/

27

byte[] encode(E event);

28

29

/**

30

* Get footer bytes to write at the end of the output.

31

* @return footer bytes, or null if no footer

32

*/

33

byte[] footerBytes();

34

}

35

```

36

37

### EncoderBase

38

39

Base implementation providing common encoder functionality and lifecycle management.

40

41

```java { .api }

42

/**

43

* Base encoder implementation with lifecycle management.

44

*/

45

public abstract class EncoderBase<E> extends ContextAwareBase implements Encoder<E> {

46

private boolean started = false;

47

48

/**

49

* Check if the encoder is started.

50

* @return true if started

51

*/

52

public boolean isStarted();

53

54

/**

55

* Start the encoder. Subclasses should override for initialization.

56

*/

57

public void start();

58

59

/**

60

* Stop the encoder. Subclasses should override for cleanup.

61

*/

62

public void stop();

63

64

/**

65

* Default implementation returns null (no header).

66

* @return null

67

*/

68

public byte[] headerBytes();

69

70

/**

71

* Default implementation returns null (no footer).

72

* @return null

73

*/

74

public byte[] footerBytes();

75

}

76

```

77

78

### LayoutWrappingEncoder

79

80

Adapter that wraps a Layout to work with the Encoder interface, providing charset conversion and immediate flush control.

81

82

```java { .api }

83

/**

84

* Encoder that wraps a Layout, converting string output to bytes.

85

* Provides the bridge between the old Layout interface and modern Encoder interface.

86

*/

87

public class LayoutWrappingEncoder<E> extends EncoderBase<E> {

88

/**

89

* Set the layout to wrap.

90

* @param layout the layout to use for formatting

91

*/

92

public void setLayout(Layout<E> layout);

93

94

/**

95

* Get the current layout.

96

* @return the wrapped layout

97

*/

98

public Layout<E> getLayout();

99

100

/**

101

* Set the character encoding for string-to-bytes conversion.

102

* @param charset the charset to use (default: UTF-8)

103

*/

104

public void setCharset(Charset charset);

105

106

/**

107

* Get the current character encoding.

108

* @return the charset being used

109

*/

110

public Charset getCharset();

111

112

/**

113

* Control immediate flush behavior (used by appenders).

114

* @param immediateFlush true to flush immediately after each event

115

*/

116

public void setImmediateFlush(boolean immediateFlush);

117

118

/**

119

* Check if immediate flush is enabled.

120

* @return true if immediate flush is enabled

121

*/

122

public boolean isImmediateFlush();

123

124

/**

125

* Encode event by calling layout.doLayout() and converting to bytes.

126

* @param event the event to encode

127

* @return UTF-8 encoded bytes of the formatted event

128

*/

129

public byte[] encode(E event);

130

}

131

```

132

133

### Layout Interface

134

135

Traditional string-based formatting interface for transforming events into formatted strings.

136

137

```java { .api }

138

/**

139

* Interface for transforming events into formatted strings.

140

* Layouts are wrapped by LayoutWrappingEncoder for modern usage.

141

*/

142

public interface Layout<E> extends ContextAware, LifeCycle {

143

/**

144

* Format an event as a string.

145

* @param event the event to format

146

* @return formatted string representation

147

*/

148

String doLayout(E event);

149

150

/**

151

* Get header string for file output.

152

* @return header string, or null if no header

153

*/

154

String getFileHeader();

155

156

/**

157

* Get footer string for file output.

158

* @return footer string, or null if no footer

159

*/

160

String getFileFooter();

161

162

/**

163

* Get header string for presentation (e.g., HTML table header).

164

* @return presentation header, or null if none

165

*/

166

String getPresentationHeader();

167

168

/**

169

* Get footer string for presentation (e.g., HTML table footer).

170

* @return presentation footer, or null if none

171

*/

172

String getPresentationFooter();

173

174

/**

175

* Get the content type of the formatted output.

176

* @return content type (e.g., "text/plain", "text/html")

177

*/

178

String getContentType();

179

}

180

```

181

182

### LayoutBase

183

184

Base implementation for layouts providing lifecycle management and default header/footer behavior.

185

186

```java { .api }

187

/**

188

* Base layout implementation with lifecycle support.

189

*/

190

public abstract class LayoutBase<E> extends ContextAwareBase implements Layout<E> {

191

private boolean started = false;

192

193

/**

194

* Check if the layout is started.

195

* @return true if started

196

*/

197

public boolean isStarted();

198

199

/**

200

* Start the layout.

201

*/

202

public void start();

203

204

/**

205

* Stop the layout.

206

*/

207

public void stop();

208

209

/**

210

* Subclasses must implement this method to format events.

211

* @param event the event to format

212

* @return formatted string

213

*/

214

public abstract String doLayout(E event);

215

216

/**

217

* Default implementation returns null (no file header).

218

* @return null

219

*/

220

public String getFileHeader();

221

222

/**

223

* Default implementation returns null (no file footer).

224

* @return null

225

*/

226

public String getFileFooter();

227

228

/**

229

* Default implementation returns null (no presentation header).

230

* @return null

231

*/

232

public String getPresentationHeader();

233

234

/**

235

* Default implementation returns null (no presentation footer).

236

* @return null

237

*/

238

public String getPresentationFooter();

239

240

/**

241

* Default implementation returns "text/plain".

242

* @return "text/plain"

243

*/

244

public String getContentType();

245

}

246

```

247

248

### EchoLayout

249

250

Simple layout that returns the event's string representation.

251

252

```java { .api }

253

/**

254

* Simple layout that returns event.toString().

255

* Useful for testing and simple output scenarios.

256

*/

257

public class EchoLayout<E> extends LayoutBase<E> {

258

/**

259

* Format event using its toString() method.

260

* @param event the event to format

261

* @return event.toString()

262

*/

263

public String doLayout(E event);

264

}

265

```

266

267

## Utility Classes

268

269

### ByteArrayUtil

270

271

Utility methods for byte array operations used in encoding.

272

273

```java { .api }

274

/**

275

* Utility methods for byte array operations.

276

*/

277

public class ByteArrayUtil {

278

/**

279

* Convert hex string to byte array at specified offset.

280

* @param hexString hex string to convert

281

* @param ba target byte array

282

* @param offset offset in target array

283

*/

284

public static void hexStringToByteArray(String hexString, byte[] ba, int offset);

285

286

/**

287

* Convert byte array to hex string.

288

* @param ba byte array to convert

289

* @return hex string representation

290

*/

291

public static String toHexString(byte[] ba);

292

}

293

```

294

295

### NonClosableInputStream

296

297

InputStream wrapper that prevents closing, useful for protecting system streams.

298

299

```java { .api }

300

/**

301

* InputStream wrapper that prevents the close() method from actually closing the stream.

302

* Useful for protecting System.in and other shared streams.

303

*/

304

public class NonClosableInputStream extends FilterInputStream {

305

/**

306

* Create a non-closable wrapper around an InputStream.

307

* @param is the input stream to wrap

308

*/

309

public NonClosableInputStream(InputStream is);

310

311

/**

312

* Override close() to do nothing, preventing actual stream closure.

313

*/

314

@Override

315

public void close();

316

}

317

```

318

319

## Usage Examples

320

321

### Basic Layout Wrapping Encoder

322

323

```java

324

import ch.qos.logback.core.encoder.LayoutWrappingEncoder;

325

import ch.qos.logback.core.layout.EchoLayout;

326

import java.nio.charset.StandardCharsets;

327

328

// Create and configure encoder with layout

329

LayoutWrappingEncoder<Object> encoder = new LayoutWrappingEncoder<>();

330

encoder.setContext(context);

331

332

// Set layout

333

EchoLayout<Object> layout = new EchoLayout<>();

334

layout.setContext(context);

335

layout.start();

336

337

encoder.setLayout(layout);

338

encoder.setCharset(StandardCharsets.UTF_8);

339

encoder.setImmediateFlush(true);

340

encoder.start();

341

342

// Use with appender

343

appender.setEncoder(encoder);

344

```

345

346

### Custom Layout Implementation

347

348

```java

349

import ch.qos.logback.core.LayoutBase;

350

import java.time.LocalDateTime;

351

import java.time.format.DateTimeFormatter;

352

353

public class TimestampLayout<E> extends LayoutBase<E> {

354

private DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

355

private String prefix = "";

356

357

@Override

358

public String doLayout(E event) {

359

StringBuilder sb = new StringBuilder();

360

sb.append('[').append(LocalDateTime.now().format(formatter)).append(']');

361

if (!prefix.isEmpty()) {

362

sb.append(' ').append(prefix);

363

}

364

sb.append(' ').append(event.toString());

365

sb.append(System.lineSeparator());

366

return sb.toString();

367

}

368

369

public void setPrefix(String prefix) {

370

this.prefix = prefix;

371

}

372

373

public String getPrefix() {

374

return prefix;

375

}

376

377

public void setDatePattern(String pattern) {

378

this.formatter = DateTimeFormatter.ofPattern(pattern);

379

}

380

381

@Override

382

public String getContentType() {

383

return "text/plain";

384

}

385

}

386

```

387

388

### Custom Encoder Implementation

389

390

```java

391

import ch.qos.logback.core.encoder.EncoderBase;

392

import java.nio.charset.StandardCharsets;

393

394

public class JsonEncoder<E> extends EncoderBase<E> {

395

private boolean includeTimestamp = true;

396

397

@Override

398

public byte[] headerBytes() {

399

return "[".getBytes(StandardCharsets.UTF_8);

400

}

401

402

@Override

403

public byte[] encode(E event) {

404

StringBuilder json = new StringBuilder();

405

json.append("{");

406

407

if (includeTimestamp) {

408

json.append("\"timestamp\":\"")

409

.append(System.currentTimeMillis())

410

.append("\",");

411

}

412

413

json.append("\"message\":\"")

414

.append(event.toString().replace("\"", "\\\""))

415

.append("\"}");

416

417

return json.toString().getBytes(StandardCharsets.UTF_8);

418

}

419

420

@Override

421

public byte[] footerBytes() {

422

return "]".getBytes(StandardCharsets.UTF_8);

423

}

424

425

public void setIncludeTimestamp(boolean includeTimestamp) {

426

this.includeTimestamp = includeTimestamp;

427

}

428

429

public boolean isIncludeTimestamp() {

430

return includeTimestamp;

431

}

432

}

433

```

434

435

### Using Encoder with File Headers and Footers

436

437

```java

438

import ch.qos.logback.core.FileAppender;

439

import ch.qos.logback.core.encoder.LayoutWrappingEncoder;

440

441

// Create encoder that produces headers and footers for XML files

442

public class XmlEncoder<E> extends EncoderBase<E> {

443

@Override

444

public byte[] headerBytes() {

445

return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<events>\n"

446

.getBytes(StandardCharsets.UTF_8);

447

}

448

449

@Override

450

public byte[] encode(E event) {

451

return String.format(" <event>%s</event>\n", event.toString())

452

.getBytes(StandardCharsets.UTF_8);

453

}

454

455

@Override

456

public byte[] footerBytes() {

457

return "</events>\n".getBytes(StandardCharsets.UTF_8);

458

}

459

}

460

461

// Use with file appender

462

FileAppender<Object> fileAppender = new FileAppender<>();

463

fileAppender.setContext(context);

464

fileAppender.setFile("events.xml");

465

466

XmlEncoder<Object> xmlEncoder = new XmlEncoder<>();

467

xmlEncoder.setContext(context);

468

xmlEncoder.start();

469

470

fileAppender.setEncoder(xmlEncoder);

471

fileAppender.start();

472

```

473

474

## Character Encoding Considerations

475

476

When working with encoders and layouts, character encoding is crucial:

477

478

- **Default Encoding**: LayoutWrappingEncoder uses UTF-8 by default

479

- **Platform Encoding**: Avoid relying on platform default encoding

480

- **Explicit Configuration**: Always set charset explicitly for predictable behavior

481

- **Byte Array Handling**: Encoders work with byte arrays, eliminating encoding ambiguity

482

483

## Migration from Layouts to Encoders

484

485

For modern logback usage, prefer encoders over layouts:

486

487

1. **Replace** `layout` configuration with `encoder`

488

2. **Wrap** existing layouts with `LayoutWrappingEncoder`

489

3. **Implement** `Encoder<E>` for new custom formatters

490

4. **Set** explicit charset on `LayoutWrappingEncoder`

491

492

The encoder approach provides better control over output format, character encoding, and integration with modern appender implementations.