Created
January 23, 2019 08:17
-
-
Save kares/c334878fe798e5e4d598c4cb9fb6576f to your computer and use it in GitHub Desktop.
Daemon thread that logs memory usage an load (for JRuby)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'logger' | |
class MonitorDaemon | |
LOG_FILE = 'monitor.log' | |
LOG_FILES_MAX = 10 * 1024 * 1024 # 10MB | |
LOG_FILES_KEEP = 10 # keep 10 (max 100MB) | |
LOGGER = begin | |
if $servlet_context && ENV_JAVA['catalina.base'] && # {tomcat_base}/logs | |
File.directory?( logs = File.join(ENV_JAVA['catalina.base'], 'logs') ) | |
Logger.new File.join(logs, LOG_FILE), LOG_FILES_KEEP, LOG_FILES_MAX | |
else | |
Logger.new "log/#{LOG_FILE}", LOG_FILES_KEEP, LOG_FILES_MAX | |
end | |
end | |
def self.start; new.start end | |
def initialize; @done = nil end | |
def start | |
thread = Thread.new { log_usage while ! @done } | |
Kernel.at_exit { @done = true; thread.join(1) } | |
end | |
SEPARATOR = ' '.freeze | |
def log_usage | |
log = '' | |
log_system_load_with_process log | |
log << SEPARATOR | |
log_heap_mem_usage log | |
log << SEPARATOR | |
log_metaspace_usage log | |
log << SEPARATOR | |
log_class_space_usage log | |
LOGGER.info log | |
sleep calc_sleep_time | |
rescue => e | |
LOGGER.warn "#{e.inspect}\n #{(e.backtrace || []).join("\n ")}"; @done = :error | |
end | |
def log_heap_mem_usage(log) | |
usage = get_heap_mem_usage | |
percent = (usage.used / usage.max.to_f) * 100 | |
log << "HeapMem: #{format_bytes(usage.used)} / #{format_bytes(usage.max)} #{sprintf('%#2d', percent)}%" | |
end | |
def log_metaspace_usage(log) | |
return unless usage = get_metaspace_usage | |
if usage.max == -1 | |
log << "MetaSpace: #{format_bytes(usage.used)} / #{'undefined'} #{' -'}%" | |
else | |
percent = (usage.used / usage.max.to_f) * 100 | |
log << "MetaSpace: #{format_bytes(usage.used)} / #{format_bytes(usage.max)} #{sprintf('%#2d', percent)}%" | |
end | |
end | |
def log_class_space_usage(log) | |
return unless usage = get_class_space_usage | |
percent = (usage.used / usage.max.to_f) * 100 | |
log << "CompClassSpace: #{format_bytes(usage.used)} / #{format_bytes(usage.max)} #{sprintf('%#2d', percent)}%" | |
end | |
def log_system_load_with_process(log) | |
return log_system_load unless pcs = get_process_load_percent | |
return unless sys = get_system_load_average | |
log << "LoadAvg: #{sprintf "%#7.4f", sys.round(4)} - JVM Using: #{sprintf('%#2d', ((pcs * 1000) / 10.0))}%" | |
end | |
protected | |
def get_system_load_average | |
mem_mx = java.lang.management.ManagementFactory.getOperatingSystemMXBean | |
avg = mem_mx.getSystemLoadAverage; avg.to_i == -1 ? nil : avg | |
end | |
def get_process_load_percent | |
name = javax.management.ObjectName.getInstance("java.lang:type=OperatingSystem") | |
list = mbean_server.getAttributes name, ['ProcessCpuLoad'] | |
return nil if list.empty? | |
list[0].value # ProcessCpuLoad is the % CPU of current JVM for the system | |
end | |
def get_heap_mem_usage | |
mem_mx = java.lang.management.ManagementFactory.getMemoryMXBean | |
mem_mx.getHeapMemoryUsage | |
end | |
def get_metaspace_usage # assuming Java 8 | |
get_memory_pool_mxbean_usage /Metaspace/ | |
end | |
def get_class_space_usage | |
get_memory_pool_mxbean_usage /Class Space/ # Compressed Class Space | |
end | |
def get_memory_pool_mxbean_usage(name_re) | |
pool_mx = java.lang.management.ManagementFactory.getMemoryPoolMXBeans | |
pool_mx = pool_mx.find { |pool| pool.name =~ name_re } | |
pool_mx ? pool_mx.getUsage : nil | |
end | |
private :get_memory_pool_mxbean_usage | |
def mbean_server | |
java.lang.management.ManagementFactory.getPlatformMBeanServer | |
end | |
# | |
def calc_sleep_time | |
normal, three_quart, geting_full = 15, 3, 1.5 # seconds | |
return normal unless usage = get_metaspace_usage | |
return geting_full if (usage.used / usage.max.to_f) >= 0.90 | |
return three_quart if (usage.used / usage.max.to_f) >= 0.75 | |
normal | |
end | |
private | |
def format_bytes(count) | |
sprintf "%#6.1f MB", (count / (1000 * 1024)).round(2) | |
end | |
end | |
MonitorDaemon.start if defined?(JRUBY_VERSION) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment