Getting daily error overview

I only find errors if I’m actively looking for them, which I only do when writing a script, or when I empirically notice something doesn’t work.

But that’s not really a sustainable approach… So now I’m wondering whether there’s a way to get a daily overview of all the errors that were logged into events.log (or even better: in any selected log file(s)). Or maybe any chosen keyword(s) to look for?

But I wouldn’t know how or where to begin. Maybe that’s more a job for an Linux cronjob, rather than an openHAB rule?

Thanks for anyone’s ideas! :slight_smile:

1 Like

Thanks! Let’s play around with that!

I do have two questions “off the bat”:

  1. Does the binding read the entire log file, or only the latest entry? Why would one configure refreshRate to 1000 ms?
  2. Why are the “default” regex values ERROR+ and WARN+? Why is the + there? What’s the added value of also matching strings like ERRORRRRRRRR and WARNNNN? :slight_smile:

It reads the logfile every 1000ms. Mine is set to 120000ms, so I get new entries every 2 minutes via push notification.

From regex101.com:

  • matches the previous token between one and unlimited times, as many times as possible, giving back as needed (greedy)

I have a rule in place which gets triggered by

items.YourItemFromChannelLogreaderLastError.state.includes("ErrorTextFromLog")

to send push notifications …

It hasn’t missed any errors yet :innocent:

Yes, that was my point. What’s the added value of also matching strings like ERRORRRRRRRR and WARNNNN? :slight_smile:

I’m still struggling with writing the errors to an overview file. Writing to an external file is apparently not that easy (although the topics I read (e.g. Writing to a text file) were fairly old).

I now have this script:

var kopieerscript = "/var/log/openhab/foutmeldingnaarbestand.sh";
var kopieeractie = actions.Exec.executeCommandLine(time.Duration.ofSeconds(2), kopieerscript, "piep");
console.log("kopieeractie = "+kopieeractie);

… with /var/log/openhab/foutmeldingnaarbestand.sh being:

#!/bin/bash
echo "$1" > foutmeldingenoverzicht.log
erik@MinipcLG2:/var/log/openhab$ ls -pal | grep -i fout
-rw-rw-r--  1 openhab openhab        21 dec 28 15:13 foutmeldingenoverzicht.log
-rwxrwxr-x  1 openhab openhab        51 dec 28 15:17 foutmeldingnaarbestand.sh

This logs:

15:18:11.373 [INFO ] [utomation.jsscripting.rule.scratchpad] - kopieeractie =

But no result:

erik@MinipcLG2:/var/log/openhab$ sudo cat foutmeldingenoverzicht.log
erik@MinipcLG2:/var/log/openhab$

If I “manually” run the script, it does work:

erik@MinipcLG2:/var/log/openhab$ sudo -u openhab bash foutmeldingnaarbestand.sh "kiekeboe"
erik@MinipcLG2:/var/log/openhab$ sudo cat foutmeldingenoverzicht.log
kiekeboe
erik@MinipcLG2:/var/log/openhab$

Anyone any idea?

You can do it with

tail -f /var/log/openhab/openhab.log /var/log/openhab/events.log \
| grep -E '\[(Error|warn)\]' \
> openhab_error_warn.log &

This would then be a regular cron job, withouth the binding an an OH script/rule, right?

The binding filters the errors automatically, so no need to create one.

My understanding is that it filters subsequent errors, not only the first one.
At least that is what I see while using that binding.

Edit:

2025-12-28 12:02:17.180 [ERROR] [.openhab.core.thing....

It filters on subsequent ERROR parts.

Yes, in the Linux terminal

That is if you find it practical to get a notification for every error… I think that might quickly get out of hand. No?

Maybe if it were (ERROR)+ then. Also: of ERROR is in an entry once, it gets detected, so if that substring is in the entry more than once, it gets detected anyway…

Is my thinking. :slight_smile:

Another approach ist to instruct the logger to additionally make a log entry into a seperate file if the log level is WARN or ERROR.

For this I changed the logger config file log4j2.xml and added this:

<RollingFile fileName="${sys:openhab.logdir}/critical.log" filePattern="${sys:openhab.logdir}/critical.log.%i.gz" name="CRITICAL">
  <Filters>
    <RegexFilter onMatch="DENY" onMismatch="NEUTRAL" regex=".*Attempting to send a state update of an item which doesn't exist.*" useRawMsg="false"/>
    <RegexFilter onMatch="DENY" onMismatch="NEUTRAL" regex=".*Cannot determine master volume level - assuming 100.*" useRawMsg="false"/>
    <RegexFilter onMatch="DENY" onMismatch="NEUTRAL" regex=".*Stopped without executing or closing null.*" useRawMsg="false"/>
    <RegexFilter onMatch="DENY" onMismatch="NEUTRAL" regex=".*(test|Test|vLog).*" useRawMsg="false"/>
    <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
  </Filters>
  <JsonTemplateLayout eventDelimiter="," eventTemplateUri="file:///etc/openhab/misc/log4j2template.json" locationInfoEnabled="true"/>
  <Policies>
    <OnStartupTriggeringPolicy/>
    <SizeBasedTriggeringPolicy size="1 MB"/>
  </Policies>
  <DefaultRolloverStrategy max="7"/>
</RollingFile>

This generates a json file which the can be directly pulled from a rule and provided to an oh-repeater control without any modification.

If interested I could post the rest of the changes required.

1 Like

That looks promising! That also seems to capture all logs, even those to other log files, right?

I’m interested!

Adding AppenderRefs to the loggers in log4j2.xml:

	<Loggers>
		<!-- Root logger configuration -->
		<Root level="WARN">
			<AppenderRef ref="LOGFILE"/>
			<AppenderRef ref="OSGI"/>
			<AppenderRef ref="CRITICAL"/>
		</Root>

		<!-- Karaf Shell logger -->
		<Logger level="OFF" name="org.apache.karaf.shell.support">
			<AppenderRef ref="STDOUT"/>
			<AppenderRef ref="CRITICAL"/>
		</Logger>

		<!-- openHAB specific logger configuration -->
		<Logger level="INFO" name="org.openhab"/>
		<Logger level="ERROR" name="openhab.event.ItemStateEvent"/>
		<Logger level="ERROR" name="openhab.event.ItemStateUpdatedEvent"/>
		<Logger level="ERROR" name="openhab.event.GroupStateUpdatedEvent"/>
		<Logger level="ERROR" name="openhab.event.ItemAddedEvent"/>
		<Logger level="ERROR" name="openhab.event.ItemRemovedEvent"/>
		<Logger level="ERROR" name="openhab.event.ItemChannelLinkAddedEvent"/>
		<Logger level="ERROR" name="openhab.event.ItemChannelLinkRemovedEvent"/>
		<Logger level="ERROR" name="openhab.event.ChannelDescriptionChangedEvent"/>
		<Logger level="ERROR" name="openhab.event.ThingStatusInfoEvent"/>
		<Logger level="ERROR" name="openhab.event.ThingAddedEvent"/>
		<Logger level="ERROR" name="openhab.event.ThingUpdatedEvent"/>
		<Logger level="ERROR" name="openhab.event.ThingRemovedEvent"/>
		<Logger level="ERROR" name="openhab.event.InboxUpdatedEvent"/>
		<Logger level="ERROR" name="openhab.event.RuleStatusInfoEvent"/>
		<Logger level="ERROR" name="openhab.event.RuleAddedEvent"/>
		<Logger level="ERROR" name="openhab.event.RuleRemovedEvent"/>
		<Logger level="ERROR" name="openhab.event.StartlevelEvent"/>
		<Logger level="ERROR" name="openhab.event.AddonEvent"/>

		<Logger additivity="false" level="INFO" name="openhab.event">
			<AppenderRef ref="EVENT"/>
			<AppenderRef ref="OSGI"/>
			<AppenderRef ref="CRITICAL"/>
		</Logger>

		<Logger level="ERROR" name="javax.jmdns"/>
		<Logger level="ERROR" name="org.jupnp"/>

		<!-- This suppresses all Maven download issues from the log when doing feature installations -->
		<!-- as we are logging errors ourselves in a nicer way anyhow. -->
		<Logger level="ERROR" name="org.ops4j.pax.url.mvn.internal.AetherBasedResolver"/>

		<!-- Filters known issues of pax-web (issue link to be added here). -->
		<!-- Can be removed once the issues are resolved in an upcoming version. -->
		<Logger level="OFF" name="org.ops4j.pax.web.pax-web-runtime"/>

		<!-- Filters known issues of lsp4j, see -->
		<!-- https://github.com/eclipse/smarthome/issues/4639 -->
		<!-- https://github.com/eclipse/smarthome/issues/4629 -->
		<!-- https://github.com/eclipse/smarthome/issues/4643 -->
		<!-- Can be removed once the issues are resolved in an upcoming version. -->
		<Logger level="OFF" name="org.eclipse.lsp4j"/>

		<!-- Filters warnings for events that could not be delivered to a disconnected client. -->
		<Logger level="ERROR" name="org.apache.cxf.jaxrs.sse.SseEventSinkImpl"/>

		<!-- Filters warnings from broken connections during startup -->
		<!-- https://github.com/openhab/openhab-core/issues/2998 -->
		<Logger level="ERROR" name="org.apache.cxf.phase.PhaseInterceptorChain"/>

		<!-- Filters known issues of KarServiceImpl, see -->
		<!-- https://github.com/openhab/openhab-distro/issues/519#issuecomment-351944506 -->
		<!-- Can be removed once the issues are resolved in an upcoming version. -->
		<Logger level="ERROR" name="org.apache.karaf.kar.internal.KarServiceImpl"/>

		<!-- Filters warnings about unavailable ciphers when JCE is not installed, see -->
		<!-- https://github.com/openhab/openhab-distro/issues/999 -->
		<Logger level="ERROR" name="org.apache.karaf.shell.ssh.SshUtils"/>

		<!-- Filters known issues of javax.mail, see -->
		<!-- https://github.com/openhab/openhab-addons/issues/5530 -->
		<Logger level="ERROR" name="javax.mail"/>

		<!-- Filters disconnection warnings of the ChromeCast Java API, see -->
		<!-- https://github.com/openhab/openhab-addons/issues/3770 -->
		<Logger name="su.litvak.chromecast.api.v2.Channel"/>

		<!-- Added by Karaf to prevent debug logging loops, see -->
		<!-- https://issues.apache.org/jira/browse/KARAF-5559 -->
		<Logger level="WARN" name="org.apache.sshd"/>
		<Logger name="org.openhab.binding.connectedcar"/>
		<Logger level="WARN" name="org.openhab.binding.shelly"/>
	</Loggers>

Template for new log file
This will change the format of our new log file. In our case a json stream. Adjust the path and file name in xml tag JsonTemplateLayout, attribute eventTemplateUri

{
  "timestamp": {
    "$resolver": "timestamp",
    "pattern": {
      "format": "yyyy-MM-dd'T'HH:mm:ss.SSS",
      "timeZone": "CET"
    }
  },
  "level": {
    "$resolver": "level",
    "field": "name"
  },
  "message": {
    "$resolver": "message",
    "stringified": true
  },
  "threadName": {
    "$resolver": "thread",
    "field": "name"
  },
  "threadId": {
    "$resolver": "thread",
    "field": "id"
  },
  "loggerName": {
    "$resolver": "logger",
    "field": "name"
  },
  "loggerFQCN": {
    "$resolver": "logger",
    "field": "fqcn"
  },
  "labels": {
    "$resolver": "mdc",
    "flatten": true,
    "stringified": true
  },
  "tags": {
    "$resolver": "ndc"
  },
  "marker": {
    "$resolver": "marker",
    "field": "name"
  },
  "errorType": {
    "$resolver": "exception",
    "field": "className"
  },
  "errorMessage": {
    "$resolver": "exception",
    "field": "message"
  },
  "errorStacktrace": {
    "$resolver": "exception",
    "field": "stackTrace",
    "stackTrace": {
      "stringified": true
    }
  }
}

Rule to import the critical.log file into an item:

var Paths = Java.type("java.nio.file.Paths");
var Files = Java.type("java.nio.file.Files");
var StandardCharsets = Java.type("java.nio.charset.StandardCharsets");

var path = Paths.get("/var/log/openhab/critical.log");

if (Files.exists(path)) {
  var content = Files.readString(path, StandardCharsets.UTF_8).trim();
  if (content.endsWith(",")) {
    content = content.replace(/,\s*$/, "");
  }
  content = "[" + content + "]";
  var count = JSON.parse(content).length;
  
  items.vLog.postUpdate(content);
  items.vLogCount.postUpdate(count);
}

List which contains all log entries and opens a popup when you click on a list-item:

    - component: f7-list
      config:
        bg-color: white
        class: -list
        inset: true
        mediaList: true
        noHairlinesBetween: false
      slots:
        default:
          - component: oh-repeater
            config:
              for: rLog
              fragment: true
              in: =JSON.parse(@@'vLog')
              sourceType: array
            slots:
              default:
                - component: oh-list-item
                  config:
                    action: variable
                    actionVariable: logDetails
                    actionVariableValue: =JSON.stringify(loop.rLog_source[loop.rLog_idx])
                    badge: =loop.rLog.level
                    badgeColor: =(loop.rLog.level == "WARN")?"yellow":"red"
                    popupOpen: =".open-popup-logdetails"
                    subtitle: =loop.rLog.timestamp + ", " + loop.rLog.threadName
                    title: =loop.rLog.message
    - component: f7-popup
      config:
        class: ="open-popup-logdetails"
        closeByBackdropClick: true
        closeOnEscape: true
        style:
          overflow-y: visible
        swipeToClose: false
      slots:
        default:
          - component: widget:popup-logdetails
            config: {}

Popup window with log details:

uid: popup-logdetails
tags:
  - expanded-card-status
props:
  parameters: []
  parameterGroups: []
timestamp: Dec 28, 2025, 8:24:56 PM
component: f7-block
config:
  style:
    --f7-navbar-bg-color: transparent
    --f7-navbar-link-color: blue
    --f7-navbar-text-color: black
    -webkit-user-drag: none
    -webkit-user-select: none
    margin: 0px
    overflow-y: visible
    padding: 0px
    user-drag: none
    user-select: none
    width: 100%
    z-index: 9999
slots:
  default:
    - component: f7-navbar
      config:
        style:
          position: sticky
        title: Details
      slots:
        right:
          - component: oh-link
            config:
              action: popup
              iconColor: black
              iconF7: multiply_circle_fill
              iconSize: = 30px
              popupClose: =".open-popup-logdetails"
    - component: Label
      config:
        style:
          -webkit-user-select: all
          margin: 10px 0px 10px 23px
          padding: 0
          user-select: all
        text: =JSON.parse(vars.logDetails).message
    - component: f7-list
      config:
        bg-color: white
        inset: true
        mediaList: false
        noHairlinesBetween: false
        style:
          --f7-list-inset-border-radius: 8px
          margin-top: 0
      slots:
        default:
          - component: oh-repeater
            config:
              for: vLog
              fragment: true
              in:
                - vId: bundle.id
                  vLabel: Bundle ID
                - vId: bundle.name
                  vLabel: Bundle Name
                - vId: bundle.version
                  vLabel: Bundle Version
                - vId: threadName
                  vLabel: Thread Name
                - vId: threadId
                  vLabel: Thread ID
                - vId: loggerName
                  vLabel: Logger Name
                - vId: loggerFQCN
                  vLabel: Logger FQCN
                - vId: labels
                  vLabel: Thread Context Data (MDC)
                - vId: tags
                  vLabel: Thread Context Stack (NDC)
                - vId: marker
                  vLabel: Marker
                - vId: errorMessage
                  vLabel: Stack Trace - Message
                - vId: errorType
                  vLabel: Stack Trace - Klasse
                - vId: errorStacktrace
                  vLabel: Stack Trace
              sourceType: array
            slots:
              default:
                - component: f7-list-item
                  config: {}
                  slots:
                    inner-start:
                      - component: Label
                        config:
                          style:
                            font-size: 12px
                            width: 110px
                          text: =loop.vLog.vLabel
                      - component: Label
                        config:
                          style:
                            -webkit-user-select: all
                            font-size: 12px
                            text-align: left
                            user-select: all
                            width: 80%
                          text: =JSON.parse(vars.logDetails)[loop.vLog.vId]

Thanks. Seems like a lot to digest though. I’ll carve some time out for it shortly!

Does this setup ‘intercept’ messages, or are they all still logged where the are logged now (in my current setup)?

It does not change the default logging logics at all. Events.log and openhab.log will not be changed.
It logs all WARN and ERRORS additionally into a seperate file.

1 Like

This would actually be a nice standard feature. I know Nextcloud has an overview of all the errors logged the previous 7 days. Would be nice if openHAB had that out of the box as well.

But in the meantime, I’ll try your proposal :wink:

Thanks!

Please note, I updated the script in my post above. The old one had problems with special characters such as umlaute, etc.