alarms: compose subtag reference from object's real Galaxy area for exact alarmmgr parity
This commit is contained in:
@@ -13,7 +13,11 @@ namespace ZB.MOM.WW.MxGateway.Server.Alarms;
|
||||
// NOTE: The exact subtag names and the canonical AlarmFullReference shape
|
||||
// ("Galaxy!{area}.{reference}") are validated against a live Galaxy in the
|
||||
// Task 17 live smoke test. The config Subtags block exists precisely so these
|
||||
// names are not hard-coded here.
|
||||
// names are not hard-coded here. The {area} is the alarm object's REAL Galaxy
|
||||
// area discovered via gobject.area_gobject_id (the alarm group the native
|
||||
// alarmmgr emits), giving exact reference parity with wnwrap. The configured
|
||||
// Discovery.Area/DefaultArea is only the fallback for explicit IncludeAttributes
|
||||
// entries, which carry no discovered area.
|
||||
public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
{
|
||||
private const string ProviderLiteral = "Galaxy";
|
||||
@@ -43,9 +47,16 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
|
||||
AlarmDiscoveryOptions discovery = options.Fallback.Discovery;
|
||||
|
||||
// Config fallback area used only for explicit IncludeAttributes entries (which
|
||||
// carry no discovered area): discovery area, else the default area (may be empty).
|
||||
string configFallbackArea = string.IsNullOrEmpty(discovery.Area) ? options.DefaultArea : discovery.Area;
|
||||
|
||||
// 1. Build the ordered, de-duplicated attribute reference set.
|
||||
// Each entry carries the reference plus the source-object reference.
|
||||
List<(string Reference, string SourceObject)> ordered = [];
|
||||
// Each entry carries the reference, the source-object reference, and the
|
||||
// per-entry area used to compose the canonical reference. GR rows contribute
|
||||
// the object's real Galaxy area; config includes contribute the config
|
||||
// fallback area (Discovery.Area else DefaultArea).
|
||||
List<(string Reference, string SourceObject, string Area)> ordered = [];
|
||||
HashSet<string> seen = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (discovery.UseGalaxyRepository)
|
||||
@@ -73,7 +84,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
continue;
|
||||
}
|
||||
|
||||
ordered.Add((row.FullTagReference, row.SourceObjectReference));
|
||||
ordered.Add((row.FullTagReference, row.SourceObjectReference, row.Area));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +95,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
continue;
|
||||
}
|
||||
|
||||
ordered.Add((include, DeriveSourceObject(include)));
|
||||
ordered.Add((include, DeriveSourceObject(include), configFallbackArea));
|
||||
}
|
||||
|
||||
// Remove excluded references (case-insensitive), but only when GR discovery
|
||||
@@ -112,12 +123,11 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
string priority = options.Fallback.Subtags.Priority;
|
||||
string ackComment = options.Fallback.Subtags.AckComment;
|
||||
|
||||
// 3. Resolve the area: discovery area, else the default area (may be empty).
|
||||
string area = string.IsNullOrEmpty(discovery.Area) ? options.DefaultArea : discovery.Area;
|
||||
|
||||
// 4. Compose one target per reference.
|
||||
// 3. Compose one target per reference, using the PER-ENTRY area: the GR row's
|
||||
// real Galaxy area (matching the alarmmgr group), or the config fallback for
|
||||
// explicit includes.
|
||||
List<AlarmSubtagTarget> targets = new(ordered.Count);
|
||||
foreach ((string reference, string sourceObject) in ordered)
|
||||
foreach ((string reference, string sourceObject, string area) in ordered)
|
||||
{
|
||||
targets.Add(new AlarmSubtagTarget
|
||||
{
|
||||
@@ -130,7 +140,7 @@ public sealed class AlarmWatchListResolver : IAlarmWatchListResolver
|
||||
});
|
||||
}
|
||||
|
||||
// 5. Report the resolved count; warn when subtag mode was expected to cover
|
||||
// 4. Report the resolved count; warn when subtag mode was expected to cover
|
||||
// something (GR enabled, or explicit includes were configured) but resolved
|
||||
// to nothing. Only emit the Debug line when there is at least one target,
|
||||
// to avoid a confusing "0 target(s)" noise line.
|
||||
|
||||
@@ -23,6 +23,18 @@ public sealed class GalaxyAlarmAttributeRow
|
||||
/// </summary>
|
||||
public string SourceObjectReference { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the owning object's Galaxy area (e.g. <c>TestArea</c>) — the alarm group.
|
||||
/// <para>
|
||||
/// Resolved via <c>gobject.area_gobject_id</c> in <c>AlarmAttributesSql</c>. The
|
||||
/// watch-list resolver composes the canonical <c>Galaxy!{area}.{reference}</c> from
|
||||
/// this so the synthesized reference's group matches the native alarmmgr (wnwrap)
|
||||
/// for reference parity. May be <see cref="string.Empty"/> when the object has no
|
||||
/// area; the resolver then falls back to the configured area.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public string Area { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the writable ack-comment attribute address.
|
||||
/// <para>
|
||||
|
||||
@@ -135,7 +135,8 @@ public sealed class GalaxyRepository(GalaxyRepositoryOptions options) : IGalaxyR
|
||||
{
|
||||
rows.Add(MapAlarmRow(
|
||||
fullTagReference: reader.GetString(0),
|
||||
sourceObjectReference: reader.GetString(1)));
|
||||
sourceObjectReference: reader.GetString(1),
|
||||
area: reader.GetString(2)));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
@@ -151,16 +152,23 @@ public sealed class GalaxyRepository(GalaxyRepositoryOptions options) : IGalaxyR
|
||||
/// schema does not expose an ack-comment address and the watch-list resolver
|
||||
/// composes it later.
|
||||
/// </para>
|
||||
/// <paramref name="area"/> is the owning object's real Galaxy area (its alarm
|
||||
/// group), resolved via <c>gobject.area_gobject_id</c>; the watch-list resolver
|
||||
/// composes the canonical reference from it so the synthesized reference's group
|
||||
/// matches what the native alarmmgr (wnwrap) emits.
|
||||
/// Exposed internally so the derivation can be unit-tested without a database.
|
||||
/// </summary>
|
||||
/// <param name="fullTagReference">The alarm-bearing attribute reference.</param>
|
||||
/// <param name="sourceObjectReference">The owning object reference (tag name).</param>
|
||||
/// <param name="area">The owning object's Galaxy area (the alarm group).</param>
|
||||
internal static GalaxyAlarmAttributeRow MapAlarmRow(
|
||||
string fullTagReference,
|
||||
string sourceObjectReference) => new()
|
||||
string sourceObjectReference,
|
||||
string area) => new()
|
||||
{
|
||||
FullTagReference = fullTagReference,
|
||||
SourceObjectReference = sourceObjectReference,
|
||||
Area = area,
|
||||
AckCommentSubtag = string.Empty,
|
||||
};
|
||||
|
||||
@@ -307,7 +315,9 @@ ORDER BY r.tag_name, r.attribute_name";
|
||||
// object. It projects just what the watch-list needs — full_tag_reference (tag_name +
|
||||
// '.' + attribute_name, matching AttributesSql) and the owning object's tag_name as
|
||||
// source_object_reference. The array `[]` suffix is intentionally omitted: an
|
||||
// alarm-bearing attribute is a scalar anchor, not an array body.
|
||||
// alarm-bearing attribute is a scalar anchor, not an array body. It also projects the
|
||||
// owning object's real Galaxy area (via gobject.area_gobject_id) as area_name so the
|
||||
// watch-list resolver composes a reference whose group matches the native alarmmgr.
|
||||
private const string AlarmAttributesSql = @"
|
||||
;WITH deployed_package_chain AS (
|
||||
SELECT g.gobject_id, p.package_id, p.derived_from_package_id, 0 AS depth
|
||||
@@ -354,8 +364,11 @@ ranked AS (
|
||||
)
|
||||
SELECT
|
||||
r.tag_name + '.' + r.attribute_name AS full_tag_reference,
|
||||
r.tag_name AS source_object_reference
|
||||
r.tag_name AS source_object_reference,
|
||||
ISNULL(area.tag_name, '') AS area_name
|
||||
FROM ranked r
|
||||
INNER JOIN gobject g ON g.gobject_id = r.gobject_id
|
||||
LEFT JOIN gobject area ON area.gobject_id = g.area_gobject_id
|
||||
WHERE r.rn = 1
|
||||
AND r.src_pri = 0
|
||||
AND EXISTS (
|
||||
|
||||
Reference in New Issue
Block a user