-
Notifications
You must be signed in to change notification settings - Fork 914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added DefaultCpuHealthChecker #4673
Changes from 11 commits
f08cb8b
08c706e
551263a
afd1843
5e5069e
e4132b4
35da7bc
a0c04bb
dd68de9
8934066
32fd4f7
0a0f815
3b1770b
c8c1664
eda64c4
a4733f9
8be0675
07c4f02
d5f162f
760496c
a1df8fa
3f4a5fc
0b14883
667a0bf
2dae89c
9d7cd92
69df576
8f2b4a1
f6ef458
a766919
f469ac7
fad1155
29048d3
20e3188
5535d6a
759763b
fb59ec4
d1a06e3
1dda317
828e51a
d619208
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Copyright 2023 LINE Corporation | ||
* | ||
* LINE Corporation licenses this file to you 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 com.linecorp.armeria.server.healthcheck; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import java.lang.management.ManagementFactory; | ||
import java.lang.management.OperatingSystemMXBean; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import com.linecorp.armeria.common.annotation.Nullable; | ||
|
||
/** | ||
* Forked from <a href="https://github.com/micrometer-metrics/micrometer/blob/8339d57bef8689beb8d7a18b429a166f6595f2af/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/system/ProcessorMetrics.java">ProcessorMetrics.java</a> in the micrometer core. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't be part of Javadoc. Could you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Fixed! |
||
public class DefaultCpuHealthChecker implements HealthChecker { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we hide the implementation from the public API, we can get more freedom on changes.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aha, so let's make this class pakage-private and add a factory method to HealthChecker! |
||
|
||
private static final List<String> OPERATING_SYSTEM_BEAN_CLASS_NAMES = ImmutableList.of( | ||
"com.ibm.lang.management.OperatingSystemMXBean", // J9 | ||
"com.sun.management.OperatingSystemMXBean" // HotSpot | ||
); | ||
|
||
private final OperatingSystemMXBean operatingSystemBean; | ||
|
||
private final Class<?> operatingSystemBeanClass; | ||
|
||
@Nullable | ||
private final Method systemCpuUsage; | ||
|
||
private final double targetCpuUsage; | ||
|
||
@Nullable | ||
private final Method processCpuUsage; | ||
|
||
private final double targetProcessCpuLoad; | ||
|
||
/** | ||
* Instantiates a new Default cpu health checker. | ||
* | ||
* @param cpuUsage the cpu usage | ||
* @param cpuIdle the cpu idle | ||
* @param processCpuUsage the process cpu usage | ||
* @param processCpuIdle the process cpu idle | ||
*/ | ||
public DefaultCpuHealthChecker(int cpuUsage, int cpuIdle, | ||
final int processCpuUsage, final int processCpuIdle) { | ||
this.targetCpuUsage = (double) cpuUsage / cpuIdle; | ||
this.targetProcessCpuLoad = (double) processCpuUsage / processCpuIdle; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question) I'm unsure why we're dividing usage by idleness. Can't we just receive two doubles There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using two is more readable. fixed it! |
||
this.operatingSystemBean = ManagementFactory.getOperatingSystemMXBean(); | ||
this.operatingSystemBeanClass = requireNonNull(getFirstClassFound(OPERATING_SYSTEM_BEAN_CLASS_NAMES)); | ||
this.systemCpuUsage = detectMethod("getSystemCpuLoad"); | ||
this.processCpuUsage = detectMethod("getProcessCpuLoad"); | ||
} | ||
|
||
@Override | ||
public boolean isHealthy() { | ||
final double currentSystemCpuUsage = invoke(systemCpuUsage); | ||
final double currentProcessCpuUsage = invoke(processCpuUsage); | ||
return currentSystemCpuUsage <= targetCpuUsage && currentProcessCpuUsage <= targetProcessCpuLoad; | ||
} | ||
|
||
private double invoke(final Method method) { | ||
try { | ||
return (double) method.invoke(operatingSystemBean); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method will be frequently invoked whenever There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the lookup#unreflect method, extracted the MethodHandle object from the Method class! |
||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | ||
return Double.NaN; | ||
} | ||
} | ||
|
||
@Nullable | ||
private Method detectMethod(final String name) { | ||
jrhee17 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
// ensure the Bean we have is actually an instance of the interface | ||
requireNonNull(operatingSystemBeanClass.cast(operatingSystemBean)); | ||
return operatingSystemBeanClass.getMethod(name); | ||
} catch (ClassCastException | NoSuchMethodException | SecurityException e) { | ||
return null; | ||
} | ||
} | ||
|
||
@Nullable | ||
private static Class<?> getFirstClassFound(final List<String> classNames) { | ||
for (String className : classNames) { | ||
try { | ||
return Class.forName(className, false, getClass().getClassLoader()); | ||
} catch (ClassNotFoundException ignore) { | ||
} | ||
} | ||
return null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also leave a link where this class was forked from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i added!