Merge pull request #38371 from jonatan-ivanov

* pr/38371:
  Add ProcessInfoContributor

Closes gh-38371
This commit is contained in:
Moritz Halbritter 2024-01-10 08:46:47 +01:00
commit 93d41497dc
8 changed files with 257 additions and 2 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import org.springframework.boot.actuate.info.GitInfoContributor;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.boot.actuate.info.JavaInfoContributor;
import org.springframework.boot.actuate.info.OsInfoContributor;
import org.springframework.boot.actuate.info.ProcessInfoContributor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -92,4 +93,11 @@ public class InfoContributorAutoConfiguration {
return new OsInfoContributor();
}
@Bean
@ConditionalOnEnabledInfoContributor(value = "process", fallback = InfoContributorFallback.DISABLE)
@Order(DEFAULT_ORDER)
public ProcessInfoContributor processInfoContributor() {
return new ProcessInfoContributor();
}
}

View File

@ -309,6 +309,12 @@
"description": "Whether to enable Operating System info.",
"defaultValue": false
},
{
"name": "management.info.process.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable process info.",
"defaultValue": false
},
{
"name": "management.metrics.binders.files.enabled",
"type": "java.lang.Boolean",

View File

@ -28,11 +28,13 @@ import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.boot.actuate.info.JavaInfoContributor;
import org.springframework.boot.actuate.info.OsInfoContributor;
import org.springframework.boot.actuate.info.ProcessInfoContributor;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.info.BuildProperties;
import org.springframework.boot.info.GitProperties;
import org.springframework.boot.info.JavaInfo;
import org.springframework.boot.info.OsInfo;
import org.springframework.boot.info.ProcessInfo;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -164,6 +166,16 @@ class InfoContributorAutoConfigurationTests {
});
}
@Test
void processInfoContributor() {
this.contextRunner.withPropertyValues("management.info.process.enabled=true").run((context) -> {
assertThat(context).hasSingleBean(ProcessInfoContributor.class);
Map<String, Object> content = invokeContributor(context.getBean(ProcessInfoContributor.class));
assertThat(content).containsKey("process");
assertThat(content.get("process")).isInstanceOf(ProcessInfo.class);
});
}
private Map<String, Object> invokeContributor(InfoContributor contributor) {
Info.Builder builder = new Info.Builder();
contributor.contribute(builder);

View File

@ -0,0 +1,58 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.info;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.info.Info.Builder;
import org.springframework.boot.actuate.info.ProcessInfoContributor.ProcessInfoContributorRuntimeHints;
import org.springframework.boot.info.ProcessInfo;
import org.springframework.context.annotation.ImportRuntimeHints;
/**
* An {@link InfoContributor} that exposes {@link ProcessInfo}.
*
* @author Jonatan Ivanov
* @since 3.3.0
*/
@ImportRuntimeHints(ProcessInfoContributorRuntimeHints.class)
public class ProcessInfoContributor implements InfoContributor {
private final ProcessInfo processInfo;
public ProcessInfoContributor() {
this.processInfo = new ProcessInfo();
}
@Override
public void contribute(Builder builder) {
builder.withDetail("process", this.processInfo);
}
static class ProcessInfoContributorRuntimeHints implements RuntimeHintsRegistrar {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.bindingRegistrar.registerReflectionHints(hints.reflection(), ProcessInfo.class);
}
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.info;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.actuate.info.ProcessInfoContributor.ProcessInfoContributorRuntimeHints;
import org.springframework.boot.info.ProcessInfo;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ProcessInfoContributor}.
*
* @author Jonatan Ivanov
*/
class ProcessInfoContributorTests {
@Test
void processInfoShouldBeAdded() {
ProcessInfoContributor processInfoContributor = new ProcessInfoContributor();
Info.Builder builder = new Info.Builder();
processInfoContributor.contribute(builder);
Info info = builder.build();
assertThat(info.get("process")).isInstanceOf(ProcessInfo.class);
}
@Test
void shouldRegisterHints() {
RuntimeHints runtimeHints = new RuntimeHints();
new ProcessInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection()
.onType(ProcessInfo.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.accepts(runtimeHints);
}
}

View File

@ -1087,12 +1087,17 @@ When appropriate, Spring auto-configures the following `InfoContributor` beans:
| Exposes Operating System information.
| None.
| `process`
| {spring-boot-actuator-module-code}/info/ProcessInfoContributor.java[`ProcessInfoContributor`]
| Exposes process information.
| None.
|===
Whether an individual contributor is enabled is controlled by its `management.info.<id>.enabled` property.
Different contributors have different defaults for this property, depending on their prerequisites and the nature of the information that they expose.
With no prerequisites to indicate that they should be enabled, the `env`, `java`, and `os` contributors are disabled by default.
With no prerequisites to indicate that they should be enabled, the `env`, `java`, `os`, and `process` contributors are disabled by default.
Each can be enabled by setting its `management.info.<id>.enabled` property to `true`.
The `build` and `git` info contributors are enabled by default.
@ -1190,6 +1195,12 @@ The `info` endpoint publishes information about your Operating System, see {spri
[[actuator.endpoints.info.process-information]]
==== Process Information
The `info` endpoint publishes information about your process, see {spring-boot-module-api}/info/ProcessInfo.html[`Process`] for more details.
[[actuator.endpoints.info.writing-custom-info-contributors]]
==== Writing Custom InfoContributors
To provide custom application information, you can register Spring beans that implement the {spring-boot-actuator-module-code}/info/InfoContributor.java[`InfoContributor`] interface.

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.info;
/**
* Information about the process of the application.
*
* @author Jonatan Ivanov
* @since 3.3.0
*/
public class ProcessInfo {
private static final Runtime runtime = Runtime.getRuntime();
private final long pid;
private final long parentPid;
private final String owner;
public ProcessInfo() {
ProcessHandle process = ProcessHandle.current();
this.pid = process.pid();
this.parentPid = process.parent().map(ProcessHandle::pid).orElse(-1L);
this.owner = process.info().user().orElse(null);
}
/**
* Number of processors available to the process. This value may change between
* invocations especially in (containerized) environments where resource usage can be
* isolated (for example using control groups).
* @return result of {@link Runtime#availableProcessors()}
* @see Runtime#availableProcessors()
*/
public int getCpus() {
return runtime.availableProcessors();
}
public long getPid() {
return this.pid;
}
public long getParentPid() {
return this.parentPid;
}
public String getOwner() {
return this.owner;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.info;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ProcessInfo}.
*
* @author Jonatan Ivanov
*/
class ProcessInfoTests {
@Test
void processInfoIsAvailable() {
ProcessInfo processInfo = new ProcessInfo();
assertThat(processInfo.getCpus()).isEqualTo(Runtime.getRuntime().availableProcessors());
assertThat(processInfo.getOwner()).isEqualTo(ProcessHandle.current().info().user().orElse(null));
assertThat(processInfo.getPid()).isEqualTo(ProcessHandle.current().pid());
assertThat(processInfo.getParentPid())
.isEqualTo(ProcessHandle.current().parent().map(ProcessHandle::pid).orElse(null));
}
}