/** Compute the amount of data promoted during a GC event. */ static long getPromotionSize(GcInfo info) { long totalBefore = getTotalUsage(info.getMemoryUsageBeforeGc()); long totalAfter = getTotalUsage(info.getMemoryUsageAfterGc()); return totalAfter - totalBefore; } }
/** * Create a new instance. * * @param info * The info object from the notification emitter on the * {@link java.lang.management.GarbageCollectorMXBean}. * @param startTime * Start time in milliseconds since the epoch. Note the info object has a start time relative * to the time the jvm process was started. */ public GcEvent(GarbageCollectionNotificationInfo info, long startTime) { this.name = info.getGcName(); this.info = info; this.type = HelperFunctions.getGcType(name); this.startTime = startTime; }
private void processGcEvent(GarbageCollectionNotificationInfo info) { GcEvent event = new GcEvent(info, jvmStartTime + info.getGcInfo().getStartTime()); gcLogs.get(info.getGcName()).add(event); if (LOGGER.isDebugEnabled()) { LOGGER.debug(event.toString()); } // Update pause timer for the action and cause... Id eventId = (isConcurrentPhase(info) ? CONCURRENT_PHASE_TIME : PAUSE_TIME) .withTag("action", info.getGcAction()) .withTag("cause", info.getGcCause()); Timer timer = Spectator.globalRegistry().timer(eventId); timer.record(info.getGcInfo().getDuration(), TimeUnit.MILLISECONDS); // Update promotion and allocation counters updateMetrics(info.getGcName(), info.getGcInfo()); // Notify an event listener if registered if (eventListener != null) { try { eventListener.onComplete(event); } catch (Exception e) { LOGGER.warn("exception thrown by event listener", e); } } }
@Override public String toString() { final GcInfo gcInfo = info.getGcInfo(); final long totalBefore = HelperFunctions.getTotalUsage(gcInfo.getMemoryUsageBeforeGc()); final long totalAfter = HelperFunctions.getTotalUsage(gcInfo.getMemoryUsageAfterGc()); final long max = HelperFunctions.getTotalMaxUsage(gcInfo.getMemoryUsageAfterGc()); String unit = "KiB"; double cnv = ONE_KIBIBYTE; if (max > ONE_GIBIBYTE) { unit = "GiB"; cnv = ONE_GIBIBYTE; } else if (max > ONE_MEBIBYTE) { unit = "MiB"; cnv = ONE_MEBIBYTE; } String change = String.format( "%.1f%s => %.1f%s / %.1f%s", totalBefore / cnv, unit, totalAfter / cnv, unit, max / cnv, unit); String percentChange = String.format( "%.1f%% => %.1f%%", 100.0 * totalBefore / max, 100.0 * totalAfter / max); final Date d = new Date(startTime); return type.toString() + ": " + name + ", id=" + gcInfo.getId() + ", at=" + d.toString() + ", duration=" + gcInfo.getDuration() + "ms" + ", cause=[" + info.getGcCause() + "]" + ", " + change + " (" + percentChange + ")"; }
/** Create a new instance. */ public GcLogger() { jvmStartTime = ManagementFactory.getRuntimeMXBean().getStartTime(); for (GarbageCollectorMXBean mbean : ManagementFactory.getGarbageCollectorMXBeans()) { CircularBuffer<GcEvent> buffer = new CircularBuffer<>(BUFFER_SIZE); gcLogs.put(mbean.getName(), buffer); } for (MemoryPoolMXBean mbean : ManagementFactory.getMemoryPoolMXBeans()) { if (HelperFunctions.isYoungGenPool(mbean.getName())) { youngGenPoolName = mbean.getName(); } if (HelperFunctions.isOldGenPool(mbean.getName())) { oldGenPoolName = mbean.getName(); } } }
/** Create a new instance. */ @Inject Plugin(Registry registry, Config config) { final boolean enabled = config.getBoolean(ENABLED_PROP, true); if (enabled) { if (config.getBoolean("spectator.gc.loggingEnabled", true)) { GC_LOGGER.start(null); LOGGER.info("gc logging started"); } else { LOGGER.info("gc logging is not enabled"); } Jmx.registerStandardMXBeans(registry); } else { LOGGER.debug("plugin not enabled, set " + ENABLED_PROP + "=true to enable"); } } }
@Override public void stop() { LOGGER.info("stopping poller"); reporter.stop(); gcLogger.stop(); if (sidecarRegistry != null) { sidecarRegistry.stop(); } }
/** Return the current set of GC events in the in-memory log. */ public List<GcEvent> getLogs() { final List<GcEvent> logs = new ArrayList<>(); for (CircularBuffer<GcEvent> buffer : gcLogs.values()) { logs.addAll(buffer.toList()); } Collections.sort(logs, GcEvent.REVERSE_TIME_ORDER); return logs; }
/** * Start collecting data about GC events. * * @param listener * If not null, the listener will be called with the event objects after metrics and the * log buffer is updated. */ public synchronized void start(GcEventListener listener) { // TODO: this class has a bad mix of static fields used from an instance of the class. For now // this has been changed not to throw to make the dependency injection use-cases work. A // more general refactor of the GcLogger class is needed. if (notifListener != null) { LOGGER.warn("logger already started"); return; } eventListener = listener; notifListener = new GcNotificationListener(); for (GarbageCollectorMXBean mbean : ManagementFactory.getGarbageCollectorMXBeans()) { if (mbean instanceof NotificationEmitter) { final NotificationEmitter emitter = (NotificationEmitter) mbean; emitter.addNotificationListener(notifListener, null, null); } } }
private void processGcEvent(GarbageCollectionNotificationInfo info) { GcEvent event = new GcEvent(info, jvmStartTime + info.getGcInfo().getStartTime()); gcLogs.get(info.getGcName()).add(event); if (LOGGER.isDebugEnabled()) { LOGGER.debug(event.toString()); } // Update pause timer for the action and cause... Id eventId = (isConcurrentPhase(info) ? CONCURRENT_PHASE_TIME : PAUSE_TIME) .withTag("action", info.getGcAction()) .withTag("cause", info.getGcCause()); Timer timer = Spectator.globalRegistry().timer(eventId); timer.record(info.getGcInfo().getDuration(), TimeUnit.MILLISECONDS); // Update promotion and allocation counters updateMetrics(info.getGcName(), info.getGcInfo()); // Notify an event listener if registered if (eventListener != null) { try { eventListener.onComplete(event); } catch (Exception e) { LOGGER.warn("exception thrown by event listener", e); } } }
@Override public String toString() { final GcInfo gcInfo = info.getGcInfo(); final long totalBefore = HelperFunctions.getTotalUsage(gcInfo.getMemoryUsageBeforeGc()); final long totalAfter = HelperFunctions.getTotalUsage(gcInfo.getMemoryUsageAfterGc()); final long max = HelperFunctions.getTotalMaxUsage(gcInfo.getMemoryUsageAfterGc()); String unit = "KiB"; double cnv = ONE_KIBIBYTE; if (max > ONE_GIBIBYTE) { unit = "GiB"; cnv = ONE_GIBIBYTE; } else if (max > ONE_MEBIBYTE) { unit = "MiB"; cnv = ONE_MEBIBYTE; } String change = String.format( "%.1f%s => %.1f%s / %.1f%s", totalBefore / cnv, unit, totalAfter / cnv, unit, max / cnv, unit); String percentChange = String.format( "%.1f%% => %.1f%%", 100.0 * totalBefore / max, 100.0 * totalAfter / max); final Date d = new Date(startTime); return type.toString() + ": " + name + ", id=" + gcInfo.getId() + ", at=" + d.toString() + ", duration=" + gcInfo.getDuration() + "ms" + ", cause=[" + info.getGcCause() + "]" + ", " + change + " (" + percentChange + ")"; }
/** Create a new instance. */ public GcLogger() { jvmStartTime = ManagementFactory.getRuntimeMXBean().getStartTime(); for (GarbageCollectorMXBean mbean : ManagementFactory.getGarbageCollectorMXBeans()) { CircularBuffer<GcEvent> buffer = new CircularBuffer<>(BUFFER_SIZE); gcLogs.put(mbean.getName(), buffer); } for (MemoryPoolMXBean mbean : ManagementFactory.getMemoryPoolMXBeans()) { if (HelperFunctions.isYoungGenPool(mbean.getName())) { youngGenPoolName = mbean.getName(); } if (HelperFunctions.isOldGenPool(mbean.getName())) { oldGenPoolName = mbean.getName(); } } }
/** Create a new instance. */ @Inject Plugin(Registry registry, Config config) { final boolean enabled = config.getBoolean(ENABLED_PROP, true); if (enabled) { if (config.getBoolean("spectator.gc.loggingEnabled", true)) { GC_LOGGER.start(null); LOGGER.info("gc logging started"); } else { LOGGER.info("gc logging is not enabled"); } Jmx.registerStandardMXBeans(registry); } else { LOGGER.debug("plugin not enabled, set " + ENABLED_PROP + "=true to enable"); } } }
/** Compute the amount of data promoted during a GC event. */ static long getPromotionSize(GcInfo info) { long totalBefore = getTotalUsage(info.getMemoryUsageBeforeGc()); long totalAfter = getTotalUsage(info.getMemoryUsageAfterGc()); return totalAfter - totalBefore; } }
/** * Create a new instance. * * @param info * The info object from the notification emitter on the * {@link java.lang.management.GarbageCollectorMXBean}. * @param startTime * Start time in milliseconds since the epoch. Note the info object has a start time relative * to the time the jvm process was started. */ public GcEvent(GarbageCollectionNotificationInfo info, long startTime) { this.name = info.getGcName(); this.info = info; this.type = HelperFunctions.getGcType(name); this.startTime = startTime; }
@PreDestroy public void destroy() { gcLogger.stop(); Spectator.globalRegistry().remove(registry); } }
/** Return the current set of GC events in the in-memory log. */ public List<GcEvent> getLogs() { final List<GcEvent> logs = new ArrayList<>(); for (CircularBuffer<GcEvent> buffer : gcLogs.values()) { logs.addAll(buffer.toList()); } Collections.sort(logs, GcEvent.REVERSE_TIME_ORDER); return logs; }
/** * Start collecting data about GC events. * * @param listener * If not null, the listener will be called with the event objects after metrics and the * log buffer is updated. */ public synchronized void start(GcEventListener listener) { // TODO: this class has a bad mix of static fields used from an instance of the class. For now // this has been changed not to throw to make the dependency injection use-cases work. A // more general refactor of the GcLogger class is needed. if (notifListener != null) { LOGGER.warn("logger already started"); return; } eventListener = listener; notifListener = new GcNotificationListener(); for (GarbageCollectorMXBean mbean : ManagementFactory.getGarbageCollectorMXBeans()) { if (mbean instanceof NotificationEmitter) { final NotificationEmitter emitter = (NotificationEmitter) mbean; emitter.addNotificationListener(notifListener, null, null); } } }