Skip to content

Instantly share code, notes, and snippets.

@kares
Created January 23, 2019 08:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kares/c334878fe798e5e4d598c4cb9fb6576f to your computer and use it in GitHub Desktop.
Save kares/c334878fe798e5e4d598c4cb9fb6576f to your computer and use it in GitHub Desktop.
Daemon thread that logs memory usage an load (for JRuby)
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