0
# Metadata Management
1
2
Metadata management allows you to attach custom information to your application when registering with Spring Boot Admin. This metadata is displayed in the admin UI and can be used for filtering, organization, and monitoring purposes.
3
4
## Core Interface
5
6
### MetadataContributor
7
8
```java { .api }
9
@FunctionalInterface
10
public interface MetadataContributor {
11
/**
12
* Contribute metadata as key-value pairs
13
* @return Map of metadata entries
14
*/
15
Map<String, String> getMetadata();
16
}
17
```
18
19
## Built-in Metadata Contributors
20
21
### StartupDateMetadataContributor
22
23
```java { .api }
24
public class StartupDateMetadataContributor implements MetadataContributor {
25
@Override
26
public Map<String, String> getMetadata();
27
}
28
```
29
30
Automatically contributes the application startup timestamp.
31
32
### CompositeMetadataContributor
33
34
```java { .api }
35
public class CompositeMetadataContributor implements MetadataContributor {
36
public CompositeMetadataContributor(List<MetadataContributor> contributors);
37
38
@Override
39
public Map<String, String> getMetadata();
40
}
41
```
42
43
Combines metadata from multiple contributors into a single map.
44
45
## Custom Metadata Contributors
46
47
### Simple Metadata Contributor
48
49
```java
50
@Component
51
public class EnvironmentMetadataContributor implements MetadataContributor {
52
53
private final Environment environment;
54
55
public EnvironmentMetadataContributor(Environment environment) {
56
this.environment = environment;
57
}
58
59
@Override
60
public Map<String, String> getMetadata() {
61
Map<String, String> metadata = new HashMap<>();
62
63
// Add active profiles
64
String[] profiles = environment.getActiveProfiles();
65
metadata.put("profiles", String.join(",", profiles));
66
67
// Add environment-specific info
68
metadata.put("environment", environment.getProperty("app.environment", "unknown"));
69
metadata.put("version", environment.getProperty("app.version", "unknown"));
70
71
return metadata;
72
}
73
}
74
```
75
76
### Build Information Contributor
77
78
```java
79
@Component
80
public class BuildMetadataContributor implements MetadataContributor {
81
82
private final BuildProperties buildProperties;
83
84
public BuildMetadataContributor(BuildProperties buildProperties) {
85
this.buildProperties = buildProperties;
86
}
87
88
@Override
89
public Map<String, String> getMetadata() {
90
Map<String, String> metadata = new HashMap<>();
91
92
if (buildProperties != null) {
93
metadata.put("build.version", buildProperties.getVersion());
94
metadata.put("build.time", buildProperties.getTime().toString());
95
metadata.put("build.artifact", buildProperties.getArtifact());
96
metadata.put("build.group", buildProperties.getGroup());
97
}
98
99
return metadata;
100
}
101
}
102
```
103
104
### Git Information Contributor
105
106
```java
107
@Component
108
public class GitMetadataContributor implements MetadataContributor {
109
110
private final GitProperties gitProperties;
111
112
public GitMetadataContributor(GitProperties gitProperties) {
113
this.gitProperties = gitProperties;
114
}
115
116
@Override
117
public Map<String, String> getMetadata() {
118
Map<String, String> metadata = new HashMap<>();
119
120
if (gitProperties != null) {
121
metadata.put("git.branch", gitProperties.getBranch());
122
metadata.put("git.commit.id", gitProperties.getShortCommitId());
123
metadata.put("git.commit.time", gitProperties.getCommitTime().toString());
124
}
125
126
return metadata;
127
}
128
}
129
```
130
131
### System Information Contributor
132
133
```java
134
@Component
135
public class SystemMetadataContributor implements MetadataContributor {
136
137
@Override
138
public Map<String, String> getMetadata() {
139
Map<String, String> metadata = new HashMap<>();
140
141
// JVM information
142
metadata.put("java.version", System.getProperty("java.version"));
143
metadata.put("java.vendor", System.getProperty("java.vendor"));
144
145
// System information
146
metadata.put("os.name", System.getProperty("os.name"));
147
metadata.put("os.arch", System.getProperty("os.arch"));
148
149
// Runtime information
150
Runtime runtime = Runtime.getRuntime();
151
metadata.put("jvm.max.memory", String.valueOf(runtime.maxMemory()));
152
metadata.put("jvm.processors", String.valueOf(runtime.availableProcessors()));
153
154
// Container/hostname info
155
try {
156
metadata.put("hostname", InetAddress.getLocalHost().getHostName());
157
} catch (UnknownHostException e) {
158
metadata.put("hostname", "unknown");
159
}
160
161
return metadata;
162
}
163
}
164
```
165
166
## Configuration-Based Metadata
167
168
### Properties Configuration
169
170
```properties
171
# Static metadata via properties
172
spring.boot.admin.client.instance.metadata.environment=production
173
spring.boot.admin.client.instance.metadata.team=backend
174
spring.boot.admin.client.instance.metadata.region=us-east-1
175
spring.boot.admin.client.instance.metadata.version=1.2.3
176
spring.boot.admin.client.instance.metadata.deployed-by=jenkins
177
```
178
179
### YAML Configuration
180
181
```yaml
182
spring:
183
boot:
184
admin:
185
client:
186
instance:
187
metadata:
188
environment: production
189
team: backend
190
region: us-east-1
191
version: 1.2.3
192
deployed-by: jenkins
193
custom-tag: custom-value
194
```
195
196
## Conditional Metadata Contributors
197
198
### Profile-Based Contributor
199
200
```java
201
@Component
202
@Profile("production")
203
public class ProductionMetadataContributor implements MetadataContributor {
204
205
@Override
206
public Map<String, String> getMetadata() {
207
Map<String, String> metadata = new HashMap<>();
208
metadata.put("environment", "production");
209
metadata.put("monitoring.level", "enhanced");
210
return metadata;
211
}
212
}
213
```
214
215
### Property-Conditional Contributor
216
217
```java
218
@Component
219
@ConditionalOnProperty(value = "app.metadata.kubernetes.enabled", havingValue = "true")
220
public class KubernetesMetadataContributor implements MetadataContributor {
221
222
@Override
223
public Map<String, String> getMetadata() {
224
Map<String, String> metadata = new HashMap<>();
225
226
// Read from Kubernetes downward API
227
metadata.put("k8s.namespace", System.getenv("POD_NAMESPACE"));
228
metadata.put("k8s.pod.name", System.getenv("POD_NAME"));
229
metadata.put("k8s.node.name", System.getenv("NODE_NAME"));
230
231
return metadata;
232
}
233
}
234
```
235
236
## Dynamic Metadata Updates
237
238
While metadata is typically static at registration time, you can implement dynamic updates:
239
240
```java
241
@Component
242
@Scheduled(fixedRate = 60000) // Update every minute
243
public class DynamicMetadataService {
244
245
private final ApplicationRegistrator registrator;
246
247
public DynamicMetadataService(ApplicationRegistrator registrator) {
248
this.registrator = registrator;
249
}
250
251
@Scheduled(fixedRate = 300000) // Re-register every 5 minutes with updated metadata
252
public void updateMetadata() {
253
// This will trigger re-registration with current metadata
254
registrator.register();
255
}
256
}
257
```
258
259
## Metadata Best Practices
260
261
### Useful Metadata Categories
262
263
- **Environment**: `environment=production`, `stage=staging`
264
- **Version**: `version=1.2.3`, `build=456`
265
- **Team/Owner**: `team=backend`, `owner=user-service-team`
266
- **Location**: `region=us-east-1`, `datacenter=dc1`
267
- **Technology**: `framework=spring-boot`, `database=postgresql`
268
- **Deployment**: `deployed-by=jenkins`, `deployed-at=2023-12-01T10:00:00Z`
269
270
### Performance Considerations
271
272
- Keep metadata lightweight (avoid large values)
273
- Cache expensive computations in metadata contributors
274
- Use conditional contributors to avoid unnecessary work
275
- Consider the frequency of metadata updates
276
277
### Security Considerations
278
279
- Avoid including sensitive information in metadata
280
- Be careful with environment variables that might contain secrets
281
- Consider which metadata is appropriate for different environments