[Solved][RELEASE] How to catch errors in log?

Can I subscribe to an event to generally catch errors mentioned in the log?
(Or is there any other way?)

In this example the Chromecast Audio Driver raises sometimes (every 2 or 3 days) that error, which would be easy to fix automatically (via "Initialize", "Refresh", and "Speak"). When I don't do this in time, Hubitat looses completly the connection to the device.

When I only could subscribe to the log stream... (BTW: the list of events of this device is empty for this timestamp)

Caveat: This is not about the Chromecast Audio Driver, but about central error processing.

Within your own driver, mostly--this is what try and catch are for. However, that only applies if the error was generated by code you wrote (or are calling in that code and isn't handled elsewhere). There are some things you won't be able to see this way (e.g., if you didn't imement a command for a capability and the platform tries to call the corresponding method), and it's not related to Logs per se; the connection is that unhandled exceptions in your code are automatically pushed to Logs, and this is one way to handle them yourself.

This won't help you with other devices or apps, only the device or app code you're writing. There is no official way to do that, though some have unofficially managed to scrape the (I think?) websocket live logs are sent through.

Not sure which of these is more of what you mean, but hopefully that helps a bit.

1 Like

Thanx a lot for your answer! :+1:

My problem is indeed the handling of external (not my drivers) errors.

What do you mean by "scrape the [...] websocket live logs"?
Maybe reading the HTML on http://[local HE IP]/logs and parsing that continually? :thinking:

I don't know because I've never tried. :slight_smile: But I have seen a maybe a couple community offerings that have. I'm not aware of any that are currently maintained, but you may be able to find more with a search. I do think it was a websocket (or maybe eventstream?), which drivers do have interfaces to read. But again, there is no official interface to logs, so this is not supported and could break at any time (which I suspect is what happened with previos attempts).

1 Like

Maybe parse:

ws://hubitat-ip:8080/logsocket

1 Like

You might try this:

1 Like

Thanx to @bertabcd1234, @aaiyar, and @jlv I created a minimal solution for my problem on the base of @bptworld's great code:

You can set the monitored level (when to fire an event).
Optionally you can also set (via ID or name) a list of monitored devices and apps.
BTW: The event contains the JSON string of the log line.

Hint: In Rule Machine use "Custom Attribute" as Trigger and choose "event" and "changed".

Maybe this driver is helpful also for others... :wink:

// Idea by:  Bryan (bptworld) - https://community.hubitat.com/u/bptworld
// Based on: https://community.hubitat.com/t/release-error-monitor/91317


metadata
{
  definition(name:'jsErrorMonitor', namespace:'de.schwider', author:'Jost Schwider', description:'Just Simple Error Monitor')
  {
	capability 'Actuator'
    
    attribute 'event', 'string'
  }
  
  preferences()
  {
    input 'monitorLevel', 'enum', title:'Monitor this Log Level:<br><small>(Don\'t try <b>info</b> or even <b>debug</b>!)</small>', options:['debug', 'info', 'warn', 'error'], defaultValue:'error', required:true
    input 'monitorDevices', 'string', title:'Monitor this Devices/Apps:<br><small>(Comma-separated Names or IDs; Empty=All)</small>', defaultValue:'', required:false
    input 'logType', 'enum', title:'Logging:', options:['Debug', 'Info', 'Off'], defaultValue:'Info', required:true
  }
}


void installed()
{
  logInfo 'Installing...'
  initialize ()
}


void updated() {
  logInfo 'Updating...'
  initialize ()
}


void initialize()
{
  logDebug 'Connecting...'
  interfaces.webSocket.connect 'ws://localhost:8080/logsocket'
}


void uninstalled()
{
  logInfo 'Uninstalling...'
  interfaces.webSocket.close ()
}


// Web Socket: //


void webSocketStatus(String socketStatus)
{
  logDebug socketStatus
}


void parse(String desc)
{
  Map logEvent =  new groovy.json.JsonSlurper().parseText(desc)
  // logEvent#Fields: name, msg, id, time, type, level 
  
  if (logEvent.id == device.id) return // Don't monitor the monitor itself! ;)
  if (logEvent.level != monitorLevel) return
  
  if (monitorDevices)
  {
    String[] devices = monitorDevices.split(',')*.trim()
    logDebug "$logEvent.id/$logEvent.name in $devices?"
    if (logEvent.id.toString() in devices || logEvent.name in devices) {} else return
  }
  
  logInfo desc
  sendEvent name:'event', value:desc
}


// Logging: //


void logInfo(String info)
{
  if (logType in ['Info', 'Debug']) log.info info
}


void logDebug(String debug)
{
  if (logType == 'Debug') log.debug debug
}
3 Likes

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.