Class NtfyLog4j2Appender
- All Implemented Interfaces:
org.apache.logging.log4j.core.Appender,org.apache.logging.log4j.core.filter.Filterable,org.apache.logging.log4j.core.impl.LocationAware,org.apache.logging.log4j.core.LifeCycle,org.apache.logging.log4j.core.LifeCycle2
AbstractAppender shell over the framework-neutral AlertEngine,
exposed to log4j2.xml as the <Ntfy .../> element. Configuration arrives either
through the plugin NtfyLog4j2Appender.Builder (declarative XML/JSON/YAML config) or as a pre-built NtfyConfig injected by NtfyLog4j2Installer for the programmatic one-liner install.
Every decision that matters — logger exclusion (including this library's own package), the
NO_ALERT marker gate, storm rate-limiting, digesting, payload assembly, and HTTP
publishing — lives in the engine; this class only maps a log4j2 LogEvent onto an
AlertEvent and calls AlertEngine.submit(io.github.pimak.ntfy.core.AlertEvent).
Self-diagnoses exclusively through log4j2's StatusLogger (via Log4j2Diagnostics), so no feedback loop through the application's own logging pipeline is
possible and no credential ever appears in diagnostic output.
Minimal log4j2.xml:
<Configuration>
<Appenders>
<Ntfy name="ntfy" url="https://ntfy.sh" topic="my-alerts"/>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="ntfy"/>
</Root>
</Loggers>
</Configuration>
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classPlugin builder for the<Ntfy .../>element.Nested classes/interfaces inherited from interface org.apache.logging.log4j.core.LifeCycle
org.apache.logging.log4j.core.LifeCycle.State -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringMarker name a caller attaches to a single log call to opt it out of alerting entirely (logger.error(MarkerManager.getMarker(NtfyLog4j2Appender.NO_ALERT_MARKER_NAME), ...)).Fields inherited from class org.apache.logging.log4j.core.AbstractLifeCycle
DEFAULT_STOP_TIMEOUT, DEFAULT_STOP_TIMEUNIT, LOGGERFields inherited from interface org.apache.logging.log4j.core.Appender
ELEMENT_TYPE, EMPTY_ARRAY -
Method Summary
Modifier and TypeMethodDescriptionvoidappend(org.apache.logging.log4j.core.LogEvent event) Gates on level, maps the event eagerly, and hands it to the engine, which owns all further gating and publishing.org.apache.logging.log4j.LevelThe log4j2 level this appender should be ATTACHED at —WARNonce the engine activated a warn route,ERRORotherwise.Read-only pipeline observability counters (published / suppressed / failed) for this appender.static NtfyLog4j2Appender.BuilderThe plugin builder log4j2 instantiates for an<Ntfy .../>element.voidstart()Builds anAlertEnginefrom the injected config (if present) or from the plugin attributes, starts it, and marks this appender started ONLY if the engine actually activated.booleanTears the engine down — which flushes any pending digest and drains the async queue — and then delegates tosuper.stopfor the normal appender/filter shutdown.Methods inherited from class org.apache.logging.log4j.core.appender.AbstractAppender
error, error, error, getHandler, getLayout, getName, ignoreExceptions, parseInt, requiresLocation, setHandler, toSerializable, toStringMethods inherited from class org.apache.logging.log4j.core.filter.AbstractFilterable
addFilter, getFilter, getPropertyArray, hasFilter, isFiltered, removeFilter, stopMethods inherited from class org.apache.logging.log4j.core.AbstractLifeCycle
equalsImpl, getState, getStatusLogger, hashCodeImpl, initialize, isInitialized, isStarted, isStarting, isStopped, isStopping, setStarted, setStarting, setState, setStopped, setStopping, stop, stopMethods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface org.apache.logging.log4j.core.LifeCycle
getState, initialize, isStarted, isStopped, stop
-
Field Details
-
NO_ALERT_MARKER_NAME
Marker name a caller attaches to a single log call to opt it out of alerting entirely (logger.error(MarkerManager.getMarker(NtfyLog4j2Appender.NO_ALERT_MARKER_NAME), ...)). Re-exposed fromAlertEngine.NO_ALERT_MARKER_NAMEso callers keep a stable handle instead of a magic string.- See Also:
-
-
Method Details
-
newBuilder
The plugin builder log4j2 instantiates for an<Ntfy .../>element.- Returns:
- a fresh builder
-
start
public void start()Builds anAlertEnginefrom the injected config (if present) or from the plugin attributes, starts it, and marks this appender started ONLY if the engine actually activated. A silently/partially unconfigured engine leaves the appenderisStarted() == false(the engine already reported why on the StatusLogger), which is what keeps a misconfigured<Ntfy>element from pretending to alert.- Specified by:
startin interfaceorg.apache.logging.log4j.core.LifeCycle- Overrides:
startin classorg.apache.logging.log4j.core.filter.AbstractFilterable
-
append
public void append(org.apache.logging.log4j.core.LogEvent event) Gates on level, maps the event eagerly, and hands it to the engine, which owns all further gating and publishing. The gate lives here (mirroring the Logback appender's gate and the Quarkus adapter's SEVERE gate) so the documented level contract holds even when the element is referenced from a<Root level="info">— without it, a root reference would push every INFO/DEBUG line verbatim to the ntfy topic.ERROR/FATAL always alert. WARN alerts only when the engine activated a warn route; below WARN nothing ever does, on any configuration. This is the inner of two floors:
attachLevel()keeps log4j2 from routing sub-threshold events here in the first place.- Parameters:
event- the event log4j2 is dispatching to this appender
-
stop
Tears the engine down — which flushes any pending digest and drains the async queue — and then delegates tosuper.stopfor the normal appender/filter shutdown. Null-safe when never started and safe to call twice;AlertEngine.stop()is itself idempotent. log4j2 routes the no-argumentstop()here too, so this is the single teardown path.- Specified by:
stopin interfaceorg.apache.logging.log4j.core.LifeCycle2- Overrides:
stopin classorg.apache.logging.log4j.core.filter.AbstractFilterable- Parameters:
timeout- the shutdown timeout log4j2 allowstimeUnit- the unit oftimeout- Returns:
- whether the appender stopped cleanly
-
attachLevel
public org.apache.logging.log4j.Level attachLevel()The log4j2 level this appender should be ATTACHED at —WARNonce the engine activated a warn route,ERRORotherwise. Read byNtfyLog4j2InstallerandNtfyLog4j2ReattachListenerso the attach-time floor andappend(org.apache.logging.log4j.core.LogEvent)'s own floor derive from one value and can never drift apart. Valid only afterstart(); before it (and afterstop()) it reports the safeERROR.This second floor is not redundant: an appender attached at
ERRORnever has WARN events routed to it at all, so without lowering it the in-appender gate would never see a warning to let through.Public because attaching this appender is not something only this package does: the Spring Boot starter's Log4j2 backend builds and attaches one too, and must derive its level from the same value or the two installation paths would disagree.
- Returns:
- the level this appender should be attached to a
LoggerConfigat
-
getCounters
Read-only pipeline observability counters (published / suppressed / failed) for this appender. The returned holder is stable for the appender's whole lifetime — the same instance before and afterstart()/stop()cycles and across a log4j2 reconfiguration — so the tallies are monotonic and never reset. Counters are pulled here, never logged, preserving the loop-safe design.- Returns:
- this appender's counters, never
null
-