Skip to main content
Version: Next 🚧

Observability

jGuard provides built-in observability for denial events, making it easy to detect when operations are blocked — even when third-party libraries silently swallow SecurityException.

The Problem: Swallowed Denials

When jGuard denies an operation in STRICT mode, it throws SecurityException. However, many legacy and third-party libraries catch Exception broadly:

// Common pattern in third-party libraries
try {
doSomething(); // jGuard throws SecurityException
} catch (Exception e) {
// Silently swallowed — the library continues with degraded behavior
}

This causes silent degradation that's extremely difficult to diagnose. The application appears to work, but security-sensitive operations are failing silently.

Mode-Aware Log Levels

jGuard logs every denial before throwing the exception, ensuring the log entry is visible regardless of what catches the exception.

ModeLog LevelBehavior
STRICTERRORDenials logged at ERROR, then SecurityException thrown
PERMISSIVEWARNDenials logged at WARN, then SecurityException thrown (errors allowed)
AUDITWARNDenials logged at WARN, operation allowed

In STRICT mode, denials appear as ERROR lines:

ERROR [jguard] DENIED network.outbound: package=com.vendor.lib.http, module=com.vendor.lib, args=[api.example.com:443]

This makes swallowed denials impossible to miss when monitoring ERROR-level logs — which most production logging configurations already alert on.

JMX Denial Counters

jGuard registers an always-on JMX MBean at io.jguard:type=DenialCounters that tracks denial counts in real time. No configuration needed — it's active from the moment the agent starts.

Available Metrics

AttributeDescription
TotalDenialsTotal denial count across all operations
FsReadDenialsFile read denials
FsWriteDenialsFile write denials
FsHardlinkDenialsHard link creation denials
NetConnectDenialsOutbound network connection denials
NetListenDenialsServer socket binding denials
ThreadCreateDenialsThread creation denials
NativeLoadDenialsNative library loading denials
EnvReadDenialsEnvironment variable read denials
PropReadDenialsSystem property read denials
PropWriteDenialsSystem property write denials
ProcessExecDenialsProcess execution denials
CryptoProviderDenialsCrypto provider modification denials
RuntimeExitDenialsJVM exit denials
RuntimeShutdownHookDenialsShutdown hook registration denials

Viewing with JConsole

  1. Start your application with jGuard
  2. Open JConsole: jconsole
  3. Connect to your application
  4. Navigate to MBeansio.jguardDenialCounters

Viewing with VisualVM

  1. Open VisualVM
  2. Connect to your application
  3. Open the MBeans tab
  4. Expand io.jguardDenialCountersAttributes

Programmatic Access

Access counters from your own code via the JMX API:

import javax.management.*;
import java.lang.management.ManagementFactory;

MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("io.jguard:type=DenialCounters");

long total = (long) server.getAttribute(name, "TotalDenials");
long netDenials = (long) server.getAttribute(name, "NetConnectDenials");

if (total > 0) {
log.warn("jGuard denied {} operations ({} network)", total, netDenials);
}

Prometheus Integration

Use the JMX Exporter to expose denial counters as Prometheus metrics:

# jmx_exporter_config.yaml
rules:
- pattern: 'io.jguard<type=DenialCounters><>(\w+)'
name: jguard_denial_$1
type: COUNTER
help: "jGuard denial count for $1"

Then alert on non-zero denial counts:

# prometheus alert rule
groups:
- name: jguard
rules:
- alert: JGuardDenialsDetected
expr: jguard_denial_TotalDenials > 0
for: 1m
labels:
severity: warning
annotations:
summary: "jGuard denials detected on {{ $labels.instance }}"

Datadog / Other APM

Most APM tools can collect JMX metrics. Configure your agent to collect from the io.jguard domain:

# datadog jmx conf
instances:
- jmx_url: "service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi"
conf:
- include:
domain: io.jguard
attribute:
TotalDenials:
metric_type: counter
alias: jguard.denials.total

Policy Discovery Debug Logging

Enable debug logging to see exactly how policies are discovered:

java -Djguard.log.level=debug -javaagent:jguard-agent.jar -jar app.jar

Or via Gradle:

./gradlew runWithAgent -Pjguard.logLevel=debug

Debug output shows:

  • Which JARs on the classpath contain policies
  • External policy entries found in META-INF/jguard/external/
  • The final assembled list of module policies
  • Override directory scanning results
  1. Run in STRICT mode — denials log at ERROR and throw SecurityException
  2. Monitor ERROR logs — most logging pipelines already alert on ERROR
  3. Expose JMX counters — wire into your existing monitoring (Prometheus, Datadog, etc.)
  4. Alert on non-zero denials — any denial in production likely indicates a missing entitlement or a library misbehaving
  5. Use debug logging for diagnostics — temporarily enable when troubleshooting policy issues

Next Steps