or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appender-factories.mdasync-logging.mdfilter-system.mdindex.mdlayout-system.mdlogging-factories.mdutility-classes.md

filter-system.mddocs/

0

# Filter System

1

2

Configurable filter system for controlling which log events are processed by appenders with threshold and custom filtering capabilities. The filter system provides both level-based filtering and extensible custom filter support.

3

4

## Capabilities

5

6

### FilterFactory Interface

7

8

Base SPI interface for creating custom Logback filters with Jackson-based polymorphic configuration.

9

10

```java { .api }

11

/**

12

* SPI for creating Logback Filter instances

13

*/

14

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")

15

public interface FilterFactory<E> extends Discoverable {

16

/**

17

* Build a filter instance

18

* @return configured Filter instance

19

*/

20

Filter<E> build();

21

}

22

```

23

24

### LevelFilterFactory Interface

25

26

Interface for creating level-based filters that filter events based on logging levels.

27

28

```java { .api }

29

/**

30

* Interface for creating level-based filters

31

*/

32

public interface LevelFilterFactory<E> {

33

/**

34

* Build a level filter instance

35

* @param threshold the minimum level threshold

36

* @return configured Filter instance

37

*/

38

Filter<E> build(Level threshold);

39

}

40

```

41

42

### ThresholdLevelFilterFactory

43

44

Default implementation that creates threshold filters for filtering events below a minimum log level.

45

46

```java { .api }

47

/**

48

* Creates threshold filters for minimum log levels

49

*/

50

public class ThresholdLevelFilterFactory implements LevelFilterFactory<ILoggingEvent> {

51

/**

52

* Build a threshold filter that accepts events at or above the threshold level

53

* @param threshold the minimum level threshold

54

* @return ThresholdFilter configured with the specified level

55

*/

56

@Override

57

public Filter<ILoggingEvent> build(Level threshold);

58

}

59

```

60

61

**Usage Example:**

62

63

```java

64

ThresholdLevelFilterFactory filterFactory = new ThresholdLevelFilterFactory();

65

Filter<ILoggingEvent> filter = filterFactory.build(Level.WARN);

66

67

// The filter will accept WARN, ERROR levels and reject DEBUG, INFO levels

68

FilterReply reply1 = filter.decide(infoEvent); // Returns DENY

69

FilterReply reply2 = filter.decide(warnEvent); // Returns NEUTRAL (accept)

70

FilterReply reply3 = filter.decide(errorEvent); // Returns NEUTRAL (accept)

71

```

72

73

### NullLevelFilterFactory

74

75

No-op filter factory that creates filters which always return NEUTRAL, effectively passing all events through.

76

77

```java { .api }

78

/**

79

* Creates no-op filters that always return NEUTRAL

80

*/

81

public class NullLevelFilterFactory<E> implements LevelFilterFactory<E> {

82

/**

83

* Build a no-op filter that accepts all events

84

* @param threshold ignored parameter

85

* @return Filter that always returns NEUTRAL

86

*/

87

@Override

88

public Filter<E> build(Level threshold);

89

}

90

```

91

92

**Usage Example:**

93

94

```java

95

NullLevelFilterFactory<ILoggingEvent> filterFactory = new NullLevelFilterFactory<>();

96

Filter<ILoggingEvent> filter = filterFactory.build(Level.DEBUG); // threshold ignored

97

98

// The filter will accept all events regardless of level

99

FilterReply reply = filter.decide(anyEvent); // Always returns NEUTRAL

100

```

101

102

## Filter Configuration in Appenders

103

104

Filters can be configured on appenders to control which events are processed. The AbstractAppenderFactory provides support for multiple filter configurations.

105

106

### Using Filters with Appenders

107

108

```java { .api }

109

public abstract class AbstractAppenderFactory<E> implements AppenderFactory<E> {

110

protected List<FilterFactory<E>> filterFactories = new ArrayList<>();

111

112

/**

113

* Set additional filter factories

114

* @param filterFactories list of filter factories to apply

115

*/

116

public void setFilterFactories(List<FilterFactory<E>> filterFactories);

117

118

/**

119

* Get the configured filter factories

120

* @return list of filter factories

121

*/

122

public List<FilterFactory<E>> getFilterFactories();

123

124

/**

125

* Add a single filter factory

126

* @param filterFactory the filter factory to add

127

*/

128

public void addFilterFactory(FilterFactory<E> filterFactory);

129

}

130

```

131

132

**Usage Example:**

133

134

```java

135

// Create a console appender with custom filtering

136

ConsoleAppenderFactory<ILoggingEvent> consoleAppender = new ConsoleAppenderFactory<>();

137

138

// Add a threshold filter to only show WARN and above

139

ThresholdLevelFilterFactory thresholdFilter = new ThresholdLevelFilterFactory();

140

List<FilterFactory<ILoggingEvent>> filters = new ArrayList<>();

141

filters.add(thresholdFilter);

142

143

consoleAppender.setFilterFactories(filters);

144

consoleAppender.setThreshold(Level.WARN); // This also applies threshold filtering

145

146

// Build the appender

147

LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

148

Appender<ILoggingEvent> appender = consoleAppender.build(context, "MyApp",

149

new DropwizardLayoutFactory(), thresholdFilter, new AsyncLoggingEventAppenderFactory());

150

```

151

152

## Custom Filter Implementation

153

154

You can create custom filters by implementing the FilterFactory interface:

155

156

### Custom Filter Example

157

158

```java

159

/**

160

* Example custom filter that filters by logger name pattern

161

*/

162

@JsonTypeName("logger-pattern")

163

public class LoggerPatternFilterFactory implements FilterFactory<ILoggingEvent> {

164

private String pattern;

165

private boolean include = true;

166

167

public void setPattern(String pattern) {

168

this.pattern = pattern;

169

}

170

171

public void setInclude(boolean include) {

172

this.include = include;

173

}

174

175

@Override

176

public Filter<ILoggingEvent> build() {

177

return new Filter<ILoggingEvent>() {

178

private Pattern compiledPattern = Pattern.compile(pattern);

179

180

@Override

181

public FilterReply decide(ILoggingEvent event) {

182

boolean matches = compiledPattern.matcher(event.getLoggerName()).matches();

183

184

if (include) {

185

return matches ? FilterReply.NEUTRAL : FilterReply.DENY;

186

} else {

187

return matches ? FilterReply.DENY : FilterReply.NEUTRAL;

188

}

189

}

190

};

191

}

192

}

193

```

194

195

**Usage Example:**

196

197

```java

198

// Filter to only include database-related loggers

199

LoggerPatternFilterFactory dbFilter = new LoggerPatternFilterFactory();

200

dbFilter.setPattern(".*\\.db\\..*");

201

dbFilter.setInclude(true);

202

203

// Filter to exclude noisy loggers

204

LoggerPatternFilterFactory noiseFilter = new LoggerPatternFilterFactory();

205

noiseFilter.setPattern("com\\.noisy\\..*");

206

noiseFilter.setInclude(false);

207

208

// Apply filters to an appender

209

FileAppenderFactory<ILoggingEvent> fileAppender = new FileAppenderFactory<>();

210

fileAppender.setFilterFactories(Arrays.asList(dbFilter, noiseFilter));

211

```

212

213

## Filter Chain Behavior

214

215

When multiple filters are configured on an appender, they are applied in order with the following logic:

216

217

1. **ACCEPT**: Event is immediately accepted and logged, skipping remaining filters

218

2. **DENY**: Event is immediately rejected and not logged, skipping remaining filters

219

3. **NEUTRAL**: Continue to the next filter in the chain

220

221

If all filters return NEUTRAL, the event is accepted and logged.

222

223

**Filter Chain Example:**

224

225

```java

226

// Create multiple filters

227

List<FilterFactory<ILoggingEvent>> filterChain = Arrays.asList(

228

createThresholdFilter(Level.DEBUG), // First: must be DEBUG or above

229

createLoggerPatternFilter("com.app.*"), // Second: must match logger pattern

230

createCustomBusinessFilter() // Third: custom business logic

231

);

232

233

ConsoleAppenderFactory<ILoggingEvent> appender = new ConsoleAppenderFactory<>();

234

appender.setFilterFactories(filterChain);

235

236

// Event processing:

237

// 1. ThresholdFilter: if level < DEBUG -> DENY (stop)

238

// 2. LoggerPatternFilter: if logger doesn't match -> DENY (stop)

239

// 3. CustomBusinessFilter: apply business logic -> ACCEPT/DENY/NEUTRAL

240

// 4. If all return NEUTRAL -> event is logged

241

```

242

243

## Built-in Logback Filters

244

245

You can also wrap standard Logback filters in FilterFactory implementations:

246

247

### Common Logback Filters

248

249

- **ThresholdFilter**: Filter by minimum level (provided by ThresholdLevelFilterFactory)

250

- **LevelFilter**: Filter by exact level match

251

- **RegexFilter**: Filter by regex pattern matching on formatted message

252

- **MDCFilter**: Filter by MDC (Mapped Diagnostic Context) values

253

- **EvaluatorFilter**: Filter using Groovy/Janino expressions

254

255

**Example wrapping a RegexFilter:**

256

257

```java

258

@JsonTypeName("regex")

259

public class RegexFilterFactory implements FilterFactory<ILoggingEvent> {

260

private String regex;

261

private FilterReply onMatch = FilterReply.NEUTRAL;

262

private FilterReply onMismatch = FilterReply.DENY;

263

264

@Override

265

public Filter<ILoggingEvent> build() {

266

ch.qos.logback.core.filter.Filter<ILoggingEvent> regexFilter =

267

new ch.qos.logback.core.filter.Filter<ILoggingEvent>() {

268

private Pattern pattern = Pattern.compile(regex);

269

270

@Override

271

public FilterReply decide(ILoggingEvent event) {

272

String message = event.getFormattedMessage();

273

return pattern.matcher(message).find() ? onMatch : onMismatch;

274

}

275

};

276

return regexFilter;

277

}

278

}

279

```