Class NtfyConfig

java.lang.Object
io.github.pimak.ntfy.core.NtfyConfig

public final class NtfyConfig extends Object
Immutable, framework-neutral configuration for the ntfy engine and client. Built exclusively through the fluent NtfyConfig.Builder (NtfyConfig.builder()...build()); every field is a plain JDK type so adapters can populate it from Joran setters, Spring @Configuration Properties, Quarkus @ConfigMapping, or ConfigLoader without core ever depending on a framework.

Defaults are applied by the builder (not here) so a builder that is never touched still yields a fully-populated config. Every collection-valued field is stored unmodifiable — stated as a rule rather than a list of field names, which is what let this sentence go stale once already.

  • Method Details

    • builder

      public static NtfyConfig.Builder builder()
      Returns a fresh NtfyConfig.Builder pre-loaded with every default.
    • getUrl

      public String getUrl()
    • getTopic

      public String getTopic()
    • getToken

      public String getToken()
    • getUsername

      public String getUsername()
    • getPassword

      public String getPassword()
    • getTitle

      public String getTitle()
    • getAppName

      public String getAppName()
    • getMaxStackFrames

      public int getMaxStackFrames()
    • getConnectTimeout

      public Duration getConnectTimeout()
    • getRequestTimeout

      public Duration getRequestTimeout()
    • getMaxAlertsPerWindow

      public int getMaxAlertsPerWindow()
    • getSuppressionWindow

      public Duration getSuppressionWindow()
    • getErrorPriority

      public String getErrorPriority()
    • getDigestPriority

      public String getDigestPriority()
    • getErrorTags

      public String getErrorTags()
    • getDigestTags

      public String getDigestTags()
    • getWarnTopic

      public String getWarnTopic()
      The ntfy topic WARN-level events are published to, or null/blank when WARN alerting is off (the default).

      This single value is the whole opt-in switch — see isWarnRoutingEnabled(). Set it to the same value as getTopic() to alert on warnings through the main topic at a different priority.

    • getWarnPriority

      public String getWarnPriority()
      The ntfy Priority header for WARN alerts (default default). Consulted only when isWarnRoutingEnabled() is true, and used for the WARN storm digest as well as individual WARN alerts — the warn route is deliberately uniform, so routing warnings to a quiet channel is not undone by its own digest arriving at urgent.
    • getWarnTags

      public String getWarnTags()
      The ntfy Tags header for WARN alerts and the WARN digest (default warning).
    • isWarnRoutingEnabled

      public boolean isWarnRoutingEnabled()
      True when a non-blank getWarnTopic() is configured, i.e. WARN-level events should be alerted. False by default: alerting is ERROR-only unless an operator names a destination for warnings.

      Adapters gate on this before submitting a WARN event, and AlertEngine refuses WARN events again on its own when it is false — the same double-floor discipline the Log4j2 adapter already applies to its attach level.

    • isWarnTopicFromClasspathFile

      public boolean isWarnTopicFromClasspathFile()
      True when getWarnTopic() was supplied ONLY by a classpath ntfy.properties — no ntfy.warn-topic system property and no NTFY_WARN_TOPIC environment variable. Set by ConfigLoader only.

      Mirrors isEndpointFromClasspathFile() and exists for the same reason: warn-topic names a destination and widens the volume of log content leaving the host, so on the zero-code auto-install paths it is subject to the same allow-classpath-endpoint opt-in. (Contrast include-mdc-keys, which is read from all three layers precisely because it cannot redirect where alerts go.)

      The refusal itself lives in AlertEngine.start() rather than in the three per-adapter ambient guards that handle the endpoint case. Those guards must refuse INSTALLATION outright, which only they can do; dropping an optional extra route is a decision the engine can make once for every adapter. Configs built explicitly — a <Ntfy warnTopic="…"> attribute, a <warnTopic> element, application.yml — never set this flag and are never affected.

    • getClickUrl

      public String getClickUrl()
      The URL ntfy opens when a notification is tapped (sent as the Click header), or null/blank to send no Click header. Applies to both individual error alerts and the storm digest.
    • getActions

      public String getActions()
      The pre-serialized ntfy Actions header value (action buttons) sent with both individual error alerts and the storm digest, or null/blank to send no Actions header. Set either as a raw ntfy short-format string (NtfyConfig.Builder.actionsHeader(String)) or from typed NtfyActions (NtfyConfig.Builder.actions(List)).
    • getExcludedLoggerPrefixes

      public List<String> getExcludedLoggerPrefixes()
      The unmodifiable list of logger-name prefixes excluded from alerting.
    • getExcludedExceptionTypes

      public List<String> getExcludedExceptionTypes()
      The unmodifiable list of fully qualified exception class names whose presence ANYWHERE in an event's cause chain gates the event out. Empty by default.

      Matched as whole names, not prefixes — the opposite of getExcludedLoggerPrefixes(), and deliberately so. A logger name is hierarchical, so a prefix names a subtree an operator can reason about; a class name is not, so a prefix there would silently catch unrelated types that merely share a spelling.

    • isCache

      public boolean isCache()
      Whether the ntfy server may cache published messages (true by default, matching ntfy's own default of storing them for 12 hours).

      false sends Cache: no. The message then reaches CONNECTED subscribers only: a subscriber with a momentary network problem never receives it, and since=/ poll=1 stop returning it. That is a real trade — privacy against delivery to anyone who was not listening at the time.

    • isFirebase

      public boolean isFirebase()
      Whether the ntfy server may forward published messages to Firebase Cloud Messaging ( true by default).

      Worth knowing before leaving it on: ntfy.sh is configured to use FCM, so on the default endpoint every alert — stack traces and allow-listed MDC values included — also transits Google's infrastructure. false sends Firebase: no. The cost is delivery latency on the Google Play Android client when instant delivery is off (up to 15 minutes); on a self-hosted server with no FCM configured the header is simply inert.

    • isDeliveryPolicyValueRejected

      public boolean isDeliveryPolicyValueRejected()
      True when a cache or firebase value was supplied but could not be read as a boolean, so the default was kept. Exists for the same reason as isStartupPingValueRejected(): on these two keys a silent misparse costs delivered alerts, so an unreadable value has to be reported rather than guessed at.
    • getIcon

      public String getIcon()
      URL of the icon shown beside the notification (ntfy Icon header), or null when unset. Must be a fetchable http(s) URL; a value that is not one is dropped, because a bad one is otherwise undetectable — the subscriber's client fetches the icon, not the server, so nothing on the publish path ever reports it.

      Where that drop is REPORTED depends on who is publishing. AlertEngine checks the value at start() and warns; NtfyClient has no diagnostics channel and drops it in silence. Same rule, one of the two paths simply has nowhere to say so.

      The FORMAT is not checked either way: ntfy renders JPEG and PNG only, but a URL says little about the bytes behind it.

    • getIconsByLoggerPrefix

      public Map<String,String> getIconsByLoggerPrefix()
      The unmodifiable logger-prefix → icon-URL table that overrides getIcon() for alerts, in configured order. Empty by default.

      A table rather than placeholders in a single URL, and the difference is a security one. The subscriber's client downloads the icon automatically when it DISPLAYS a notification — no tap involved — so an interpolated URL would send whatever it interpolated, plus the subscriber's IP, to a third-party host on every notification. A table only ever selects among URLs the operator wrote out in full, so nothing derived from a running application ever leaves.

      Applies to alerts only. A notification published through NtfyClient has no logger to match on and always carries getIcon().

    • isIconsByLoggerValueRejected

      public boolean isIconsByLoggerValueRejected()
      True when an icons-by-logger entry could not be read as a prefix=url pair, so it was discarded. Exists for the same reason as isStartupPingValueRejected(): without it a pair mistyped with a space instead of an = would be indistinguishable from an unset key, and would produce no icon and no signal — the invisible failure the icon URL check exists to prevent, reintroduced one layer earlier.
    • getIncludeMdcKeys

      public List<String> getIncludeMdcKeys()
      The unmodifiable, EXPLICIT allow-list of MDC keys whose values are rendered into alert bodies (one key: value line each), in configured order — that order is the rendering order. Empty by default, i.e. no MDC content is published at all unless an operator opts in.

      There is deliberately NO wildcard and no "include everything" mode: a production MDC routinely carries session tokens and user identifiers, so no MDC value may ever leave the process in a notification unless it was named here. Adapters project the live context through MdcProjector.project(java.util.List<java.lang.String>, java.util.function.Function<java.lang.String, java.lang.String>), which also scrubs, truncates, and caps whatever the named keys hold.

    • isEnabled

      public boolean isEnabled()
    • isAsyncEnabled

      public boolean isAsyncEnabled()
      True when delivery of individual error alerts should be offloaded to the engine's bounded asynchronous work queue instead of running inline on the calling (logging) thread. On by default (since 2.0): a slow or unreachable ntfy server can never back-pressure application threads during an error storm — see AlertEngine for the queue/overflow semantics. Disable it to restore the pre-2.0 synchronous behavior, where each publish blocks the calling thread until the HTTP exchange completes — useful for short-lived processes (batch jobs, CLIs) that must know the alert left the process before the logging call returns.
    • getAsyncQueueCapacity

      public int getAsyncQueueCapacity()
      Maximum number of pending error alerts the asynchronous delivery queue holds before overflow kicks in (see AlertEngine). Only consulted when isAsyncEnabled() is true. A non-positive value is clamped to a safe minimum by the engine at start.
    • isRequireHttpsForCredentials

      public boolean isRequireHttpsForCredentials()
      True when the engine must REFUSE activation (rather than merely warn) if credentials — a configured token, a username/password pair, or userinfo embedded in the URL itself — would be sent over a cleartext http:// endpoint. On by default (since 2.0): secrets never traverse the network unencrypted unless the operator explicitly opts out. Setting it to false restores the pre-2.0 warn-and-activate behavior for deliberate self-hosted plain-HTTP setups.
    • isEndpointFromClasspathFile

      public boolean isEndpointFromClasspathFile()
      True when the endpoint URL was supplied ONLY by a classpath ntfy.properties (no system property or environment variable set it). Set by ConfigLoader; auto-installing adapters use it to warn loudly, because any jar on the classpath can carry such a file and silently redirect log-derived alerts to a server the operator never chose.
    • isAllowClasspathEndpoint

      public boolean isAllowClasspathEndpoint()
      True when the operator has explicitly opted in to activating alert delivery from an endpoint URL supplied only by a classpath ntfy.properties (see isEndpointFromClasspathFile()). Default false: because any jar on the classpath can ship such a file and silently redirect log-derived alerts (messages and stack traces) to a server the operator never chose, auto-installing adapters refuse classpath-only activation unless this flag is set (kebab key allow-classpath-endpoint, env NTFY_ALLOW_CLASSPATH_ENDPOINT, sysprop ntfy.allow-classpath-endpoint).
    • getStartupPing

      public StartupPingMode getStartupPing()
      What the opt-in startup self-test does once the engine has finished activating — see StartupPingMode. Defaults to StartupPingMode.OFF, which is a true no-op: no request is made and no diagnostic line is emitted, so the default path's diagnostic stream is unchanged. Never null.
    • isStartupPingFailFast

      public boolean isStartupPingFailFast()
      True when a failed startup self-test must abort application startup (by throwing NtfyStartupSelfTestException out of AlertEngine.start()) rather than merely warn. Default false: a logging backend must never be able to kill the application it instruments, so failing the deployment is strictly opt-in.

      Enabling this also makes the self-test run inline instead of on a background thread, because a start that has already returned can no longer be aborted. That is a bounded but real addition to startup time (at most connect-timeout + request-timeout), and is the reason this is aimed at CI/staging rather than production.

      Inert when getStartupPing() is StartupPingMode.OFF; the engine warns about that combination, since it is always a mistake.

    • isStartupPingValueRejected

      public boolean isStartupPingValueRejected()
      True when a startup-ping value was supplied but matched no known mode, so the default was kept. Exists purely so the engine can warn about the typo at start: without it, a misspelled startup-ping=prob would be indistinguishable from an unset key and would silently behave as off — the exact class of silent misconfiguration this whole feature was added to eliminate.
    • getStartupPingWarn

      public StartupPingMode getStartupPingWarn()
      What the startup self-test does for the optional WARN route — see StartupPingMode. Independent of getStartupPing() and likewise StartupPingMode.OFF by default, because the two routes are configured, permissioned and paid for separately: ntfy grants access per topic, so a healthy ERROR route is no evidence at all about the WARN one, and in publish mode each route costs its own notification on every boot. Never null.

      Only consulted when the WARN route actually survived its own preconditions; testing a route the engine has withdrawn would report on something that is not going to be used.

    • isStartupPingWarnValueRejected

      public boolean isStartupPingWarnValueRejected()
      As isStartupPingValueRejected(), for startup-ping-warn.
    • isStartupPingNotifyFailures

      public boolean isStartupPingNotifyFailures()
      Whether a failed self-test should be announced as an ntfy notification on a route that PASSED. On by default — the one opt-OUT in this feature.

      A diagnostic line lands on a status manager or stderr that nobody reads until they are already investigating; the point of alerting is that it reaches people. When one route is broken and another is proven healthy, the healthy one can carry that news to where operators actually look.

      It cannot fire unless some route's self-test PASSED, which is what stops it from publishing to a topic the self-test has not just verified: with no WARN route tested, nothing fails, and the ERROR topic is never pinged. Note the one surprise it does introduce — with this on, a self-test configured purely as probe can still publish exactly one notification, the failure report. Set it false to keep probe absolutely publish-free.

    • getLocale

      public Locale getLocale()
      Language of the notification bodies and self-diagnostic messages the engine produces. Defaults to Locale.ENGLISH and, deliberately, never follows the host JVM's default locale, so the language of alerts is deterministic regardless of where the process runs. A locale with no shipped translation falls back wholesale to English; a partial translation degrades to English per missing key. Never null.
    • isActive

      public boolean isActive()
      True when this config should actually deliver alerts: it is enabled, and both getUrl() and getTopic() are non-blank. A config that is disabled or missing either endpoint half is inactive (the engine reports why via Diagnostics at start).