Skip to main content

Instance Filters

Filter which instances are visible and managed by Spring Boot Admin Server.

Overview

InstanceFilter allows you to selectively include or exclude instances from being displayed and monitored by the Admin Server.

Use Cases:

  • Hide test/development instances in production Admin Server
  • Filter instances by environment, region, or tags
  • Exclude specific services from monitoring
  • Show only instances matching certain criteria

Default Behavior

By default, all instances are visible:

@Bean
@ConditionalOnMissingBean
public InstanceFilter instanceFilter() {
return instance -> true; // Accept all instances
}

InstanceFilter Interface

package de.codecentric.boot.admin.server.services;

import de.codecentric.boot.admin.server.domain.entities.Instance;

@FunctionalInterface
public interface InstanceFilter {

/**
* Test if instance should be visible
* @param instance the instance to filter
* @return true if instance should be included, false to exclude
*/
boolean filter(Instance instance);

}

How It Works

InstanceFilter is applied by InstanceRegistry:

public Flux<Instance> getInstances() {
return repository.findAll().filter(filter::filter);
}

public Mono<Instance> getInstance(InstanceId id) {
return repository.find(id).filter(filter::filter);
}

Important: Instances are still stored in the repository, but filtered from queries. This means:

  • Filtered instances continue to be monitored
  • Events are still generated for filtered instances
  • Filtering only affects visibility in the UI and API

Filter by Environment

Show only production instances:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
String env = instance.getRegistration()
.getMetadata()
.get("environment");

return "production".equals(env);
};
}
}

Client Configuration:

spring:
boot:
admin:
client:
instance:
metadata:
environment: production

Filter by Tags

Show only instances with specific tags:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
String tags = instance.getRegistration()
.getMetadata()
.get("tags");

if (tags == null) {
return false; // Exclude instances without tags
}

// Show instances with "production" or "critical" tag
return tags.contains("production") || tags.contains("critical");
};
}
}

Client Configuration:

spring:
boot:
admin:
client:
instance:
metadata:
tags: production,critical,payment

Filter by Service Name

Exclude specific services:

package com.example.admin;

import java.util.Set;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
Set<String> excludedServices = Set.of(
"test-service",
"dev-helper",
"mock-service"
);

return instance -> {
String serviceName = instance.getRegistration().getName();
return !excludedServices.contains(serviceName);
};
}
}

Filter by Status

Show only healthy instances:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
StatusInfo status = instance.getStatusInfo();

// Show only UP or UNKNOWN instances
return status.isUp() || status.isUnknown();
};
}
}

Status values:

  • isUp() - Instance is healthy
  • isDown() - Instance is unhealthy
  • isOffline() - Instance is unreachable
  • isUnknown() - Status not yet determined

Filter by URL Pattern

Show only instances from specific hosts:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
String serviceUrl = instance.getRegistration().getServiceUrl();

// Show only instances on production domain
return serviceUrl != null &&
serviceUrl.contains(".prod.company.com");
};
}
}

Configurable Filter

Filter based on application properties:

application.yml:

admin:
filter:
enabled: true
environment: production
tags:
- critical
- production

Configuration:

package com.example.admin;

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
@EnableConfigurationProperties(FilterProperties.class)
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter(FilterProperties filterProperties) {
if (!filterProperties.isEnabled()) {
return instance -> true; // No filtering
}

return instance -> {
String env = instance.getRegistration()
.getMetadata()
.get("environment");

String tags = instance.getRegistration()
.getMetadata()
.get("tags");

// Check environment
if (filterProperties.getEnvironment() != null) {
if (!filterProperties.getEnvironment().equals(env)) {
return false;
}
}

// Check tags
if (filterProperties.getTags() != null && !filterProperties.getTags().isEmpty()) {
if (tags == null) {
return false;
}

for (String requiredTag : filterProperties.getTags()) {
if (tags.contains(requiredTag)) {
return true;
}
}
return false;
}

return true;
};
}
}

@Component
@ConfigurationProperties(prefix = "admin.filter")
class FilterProperties {
private boolean enabled = false;
private String environment;
private List<String> tags;

// Getters and setters
public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public String getEnvironment() {
return environment;
}

public void setEnvironment(String environment) {
this.environment = environment;
}

public List<String> getTags() {
return tags;
}

public void setTags(List<String> tags) {
this.tags = tags;
}
}

Multiple Conditions

Combine multiple filter conditions:

package com.example.admin;

import java.util.Set;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
Set<String> allowedEnvironments = Set.of("production", "staging");
Set<String> excludedServices = Set.of("test-service", "dev-tool");

return instance -> {
String env = instance.getRegistration()
.getMetadata()
.get("environment");

String serviceName = instance.getRegistration().getName();

// Include if:
// 1. Environment is allowed AND
// 2. Service is not excluded
return allowedEnvironments.contains(env) &&
!excludedServices.contains(serviceName);
};
}
}

Advanced Filtering

Filter by Registration Time

Show only recently registered instances:

package com.example.admin;

import java.time.Duration;
import java.time.Instant;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
Instant registrationTime = instance.getRegistration().getTimestamp();
if (registrationTime == null) {
return true;
}

// Show instances registered within last 7 days
Duration age = Duration.between(registrationTime, Instant.now());
return age.compareTo(Duration.ofDays(7)) < 0;
};
}
}

Filter by Build Info

Show only instances with specific versions:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
if (instance.getInfo() == null || instance.getInfo().getValues() == null) {
return true; // No build info available
}

Object buildInfo = instance.getInfo().getValues().get("build");
if (buildInfo instanceof Map) {
Map<?, ?> build = (Map<?, ?>) buildInfo;
String version = (String) build.get("version");

// Only show version 2.x and above
return version != null && !version.startsWith("1.");
}

return true;
};
}
}

Database-Driven Filter

Load filter rules from database:

package com.example.admin;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter(InstanceFilterRuleRepository repository) {
return instance -> {
String serviceName = instance.getRegistration().getName();
String env = instance.getRegistration()
.getMetadata()
.get("environment");

// Query database for filter rules
return repository.shouldShowInstance(serviceName, env);
};
}
}

interface InstanceFilterRuleRepository {
boolean shouldShowInstance(String serviceName, String environment);
}

Composite Filters

Combine multiple filters with AND/OR logic:

package com.example.admin;

import java.util.Arrays;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.boot.admin.server.services.InstanceFilter;

@Configuration
public class InstanceFilterConfig {

@Bean
public InstanceFilter instanceFilter() {
InstanceFilter envFilter = instance -> {
String env = instance.getRegistration()
.getMetadata()
.get("environment");
return "production".equals(env);
};

InstanceFilter statusFilter = instance -> {
return instance.getStatusInfo().isUp();
};

InstanceFilter tagsFilter = instance -> {
String tags = instance.getRegistration()
.getMetadata()
.get("tags");
return tags != null && tags.contains("monitored");
};

// Combine with AND logic
return and(envFilter, statusFilter, tagsFilter);
}

private InstanceFilter and(InstanceFilter... filters) {
return instance -> {
for (InstanceFilter filter : filters) {
if (!filter.filter(instance)) {
return false;
}
}
return true;
};
}

private InstanceFilter or(InstanceFilter... filters) {
return instance -> {
for (InstanceFilter filter : filters) {
if (filter.filter(instance)) {
return true;
}
}
return false;
};
}
}

Testing Filters

Unit Test

package com.example.admin;

import java.util.Map;

import org.junit.jupiter.api.Test;

import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.values.InstanceId;
import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.services.InstanceFilter;

import static org.assertj.core.api.Assertions.assertThat;

class InstanceFilterTest {

@Test
void shouldFilterByEnvironment() {
InstanceFilter filter = instance -> {
String env = instance.getRegistration()
.getMetadata()
.get("environment");
return "production".equals(env);
};

Instance prodInstance = createInstance("prod-service",
Map.of("environment", "production"));
Instance devInstance = createInstance("dev-service",
Map.of("environment", "development"));

assertThat(filter.filter(prodInstance)).isTrue();
assertThat(filter.filter(devInstance)).isFalse();
}

private Instance createInstance(String name, Map<String, String> metadata) {
Registration registration = Registration.builder()
.name(name)
.healthUrl("http://localhost:8080/actuator/health")
.metadata(metadata)
.build();

return Instance.create(InstanceId.of("test-id"))
.register(registration);
}
}

Troubleshooting

Issue: Instances not appearing in UI

Cause: Filter is excluding them.

Debug:

@Bean
public InstanceFilter instanceFilter() {
return instance -> {
boolean result = /* your filter logic */;

// Log for debugging
if (!result) {
System.out.println("Filtered out: " +
instance.getRegistration().getName());
}

return result;
};
}

Issue: Filter not applied

Cause: Multiple InstanceFilter beans defined.

Solution: Only define one InstanceFilter bean. Spring Boot Admin uses the first one it finds.

Issue: Metadata not available

Cause: Client not sending metadata.

Solution: Verify client configuration:

spring:
boot:
admin:
client:
instance:
metadata:
environment: production

Best Practices

  1. Keep filters simple: Complex filters can impact performance
  2. Document filter logic: Make it clear why instances are excluded
  3. Test thoroughly: Ensure correct instances are visible
  4. Use metadata: Don't filter based on volatile data like status
  5. Consider multiple Admin Servers: Instead of complex filtering, run separate Admin Servers for different environments

Examples

Example 1: Multi-Tenant Filter

@Bean
public InstanceFilter instanceFilter(@Value("${tenant.id}") String tenantId) {
return instance -> {
String instanceTenant = instance.getRegistration()
.getMetadata()
.get("tenant");
return tenantId.equals(instanceTenant);
};
}

Example 2: Region-Based Filter

@Bean
public InstanceFilter instanceFilter(@Value("${aws.region}") String currentRegion) {
return instance -> {
String instanceRegion = instance.getRegistration()
.getMetadata()
.get("region");
return currentRegion.equals(instanceRegion);
};
}

Example 3: Whitelist/Blacklist Filter

@Bean
public InstanceFilter instanceFilter(
@Value("${admin.whitelist:}") List<String> whitelist,
@Value("${admin.blacklist:}") List<String> blacklist) {

return instance -> {
String serviceName = instance.getRegistration().getName();

// Blacklist takes precedence
if (blacklist.contains(serviceName)) {
return false;
}

// If whitelist is empty, allow all (except blacklisted)
if (whitelist.isEmpty()) {
return true;
}

// Otherwise, only allow whitelisted
return whitelist.contains(serviceName);
};
}

Configuration:

admin:
whitelist:
- payment-service
- user-service
blacklist:
- test-service

See Also