How does system.alarm.queryJournal() query for "source"?

I haven't been able to find precise details on what the path and source parameters are actually querying against. I want to be exact in my tag alarm queries, because some tag paths are subsets of others (have similar names).

So far, I've found the following:

  • "*Path/To/Tag1*" returns multiple alarms (ie. Path/To/Tag1 and Path/To/Tag10 both match the former path)
  • "*Path/To/Tag1:*" avoides this problem because the source always ends with a colon (apparently)
  • "*:Path/To/Tag1*" doesn't return anything because the source doesn't start with a colon (apparently)

I would think that the source parameter would be matched against the alarm_event.source column of that db table. But this, according to my testing above, doesn't seem to be the case.

From the docs:

Qualified Paths
A qualified path in Ignition is a path to an object, described by various annotated components. Each component has a type identifier and a value, separated by a colon (:), and each component is separated by colon-forward slash (:/). For example, an alarm is identified by alm:Alarm Name. It usually exists under a Tag, in which case, its fuller path would be tag:Path/To/Tag:/alm:Alarm Name. Paths can be built up further depending on the level of specificity required by the situation.

Alarm Journal - Ignition User Manual 8.1 - Ignition Documentation

In my example, this is what would be returned by the source property on the PyAlarmEvent object:
prov:MyTagProvider:/tag:Path/To/Tag1:/alm:Alarm Name 1
So I'm confused why system.alarm.queryJournal(source="*Path/To/Tag1:*") returns the results I want, but system.alarm.queryJournal(source="*:Path/To/Tag1*") doesn't return anything.

What string is this source parameter being compared to?

Docs here: system.alarm.queryJournal - Ignition User Manual 8.1 - Ignition Documentation

I'm guessing my post here was confusing. Allow me to explain a little more.

I'm trying to understand how the system.alarm.queryJournal function interprets the source parameter. Here's some test code:

alarm_tags = system.tag.browse('[default]Alarm_Tags', filter={'tagType': 'AtomicTag'})

# Loop through all tags with alarms in the Alarm_Tags folder
for alarm_tag in alarm_tags:
	print('Tag path: {}'.format(alarm_tag['fullPath']))
	
	config = system.tag.getConfiguration(alarm_tag['fullPath'], recursive=False)[0]
	
	# Ignore tags without alarms
	if 'alarms' not in config or len(config['alarms']) == 0: continue
	print('\tTag config: {}'.format(config))

	# Remove provider from alarm path to use in source query
	source = '*{}:*'.format(str(BasicTagPath.subPath(
		alarm_tag['fullPath'],
		1,
		alarm_tag['fullPath'].getPathLength() - 1)
	))
	
	# Query alarm journal using source
	alarm_history = system.alarm.queryJournal(startDate=start, endDate=end, journalName='Alarm_Journal', source=source, includeSystem=False)
	
	print('\tSource query: {}'.format(source))

	for alarm_event in alarm_history:
		print('\t\tAlarm event source: {}'.format(alarm_event.getSource()))
	
	print

That will yield the following output (summarized):

Tag path: [default]Alarm_Tags/Path/To/Tag1
	Tag config: {'path': '[default]Alarm_Tags/Path/To/Tag1', 'name': 'Tag1', 'alarms': [{'name': 'Alarm Name 1', ...}], ...}
	Source query: *Alarm_Tags/Path/To/Tag1:*
		Alarm event source: prov:default:/tag:Alarm_Tags/Path/To/Tag1:/alm:Alarm Name 1
...

The thing I want to understand here, is why changing the source query from *Alarm_Tags/Path/To/Tag1:* to *:Alarm_Tags/Path/To/Tag1:* (colon added at beginning) results in no alarm events being found at all. That tells me that the source parameter, doesn't match against the alarm_event.getSource() value.

Put another way, *:Alarm_Tags/Path/To/Tag1:* matches prov:default:/tag:Alarm_Tags/Path/To/Tag1:/alm:Alarm Name 1, but using it for source in system.alarm.queryJournal() doesn't match any alarm events. I want to understand why that is.

Any ideas?

I would say that the leading colon is part if the tag: 'key'-- for lack of a better term-- and not part of the tag path. Just like the provider does not contain :default.

That might have explained the trailing colon working, but the leading colon doesn't work. When source='*:<tagPath>*', the journal query won't return anything.

TL/DR Don't use either the leading or trailing colon. The first example you gave is the correct filter approach.

A qualified path in Ignition is a path to an object, described by various annotated components. Each component has a type identifier and a value, separated by a colon (:), and each component is separated by colon-forward slash (:/)

This is the important part. In reference to the filter.

Neither of the colons belong to the "path". Frankly, I am surprised that the trailing colon works, I would expect it to also return nothing. Seems a bit like a "feature" to me.

In reality, as the documentation states, the :/ separates the path components. Each component is made up of a type identifier and a value separated by a :. Much like key value pairs in a Python dictionary, the colons are syntax.

In the Alarm Journal documentation the source is defined as a qualified path to the entity which generated the alarm. Meaning that it isn't necessarily a tag (thus the qualified path as opposed to a tag path). The path argument, however, is the Display path of the alarm. This is the path that will show in the journal.

3 Likes

This "feature" is exactly what I'm interested in. It's convenient to rely on, instead of filtering the results again after the initial query. But, as you recommended, I probably shouldn't rely on it, since there isn't any documentation to guarantee this functionality.

I appreciate the distinction between an entity and a tag. I think that could be important in understanding how this function works under the hood.

According to the docs, there doesn't appear to be a difference between using source vs path as inputs. I can't tell if that is because of a legacy feature, planning for a new feature where the two aren't the same, or just indecisive naming of things (which is, admittedly, hard).

The "filtering after the fact" method is working for me, so I'll give you the solution for this one, but if anyone else has more insight on this, I'd be interested to learn more about it.

If you don't customize the Display path for alarms, then there probably is little difference 99% of the time. However, it is entirely possible to set the display path of an alarm to something that is more Human Readable than a tag path (which is really not useful to operators whom aren't also OT).

From the manual:

The Display Path can be customized on each alarm. The default value for an alarm's Display Path is a Tag path that leads to the name of the alarm. ... However, the Display Path can be customized when configuring the alarm. This is generally utilized to display readable messages as to what the issue is.

and

The Source Path is also a path to the alarm, but also shows the Tag provider the alarm is located in. ... Unlike the Display Path, the Source Path on an alarm can never be overridden.

So perhaps your tag paths are very long, the display path can be used to make that more readable. Which would then make filtering by source different than filtering by display path.

2 Likes