@@ -65,32 +65,36 @@ public void validate() throws Exception {
6565 // which are in normal text as they are needed for
6666 // the filter expressions for retrieving the actual logs.
6767 log .info ("Searching for expected log: {}" , expectedAttributes );
68- String operation = (String ) expectedAttributes .get ("Operation" );
69- String remoteService = (String ) expectedAttributes .get ("RemoteService" );
70- String remoteOperation = (String ) expectedAttributes .get ("RemoteOperation" );
71- String remoteResourceType = (String ) expectedAttributes .get ("RemoteResourceType" );
72- String remoteResourceIdentifier = (String ) expectedAttributes .get ("RemoteResourceIdentifier" );
73-
7468 Map <String , Object > actualLog ;
7569
76- // Parsing unique identifiers in OTLP spans
77- if (operation == null ) {
78- operation = (String ) expectedAttributes .get ("attributes[\\ \" aws.local.operation\\ \" ]" );
79- remoteService = (String ) expectedAttributes .get ("attributes[\\ \" aws.remote.service\\ \" ]" );
80- remoteOperation = (String ) expectedAttributes .get ("attributes[\\ \" aws.remote.operation\\ \" ]" );
81- // Runtime metrics have no operation at all, we must ensure we are in the proper use case
82- if (operation != null ) {
83- actualLog = this .getActualOtelSpanLog (operation , remoteService , remoteOperation );
84- } else {
85- // No operation at all -> Runtime metric
70+ if (isOtlpSigV4Log (expectedAttributes )) {
71+ actualLog = this .getActualOtlpSigV4Log ();
72+ } else {
73+ String operation = (String ) expectedAttributes .get ("Operation" );
74+ String remoteService = (String ) expectedAttributes .get ("RemoteService" );
75+ String remoteOperation = (String ) expectedAttributes .get ("RemoteOperation" );
76+ String remoteResourceType = (String ) expectedAttributes .get ("RemoteResourceType" );
77+ String remoteResourceIdentifier = (String ) expectedAttributes .get ("RemoteResourceIdentifier" );
78+
79+ // Parsing unique identifiers in OTLP spans
80+ if (operation == null ) {
81+ operation = (String ) expectedAttributes .get ("attributes[\\ \" aws.local.operation\\ \" ]" );
82+ remoteService = (String ) expectedAttributes .get ("attributes[\\ \" aws.remote.service\\ \" ]" );
83+ remoteOperation = (String ) expectedAttributes .get ("attributes[\\ \" aws.remote.operation\\ \" ]" );
84+ // Runtime metrics have no operation at all, we must ensure we are in the proper use case
85+ if (operation != null ) {
86+ actualLog = this .getActualOtelSpanLog (operation , remoteService , remoteOperation );
87+ } else {
88+ // No operation at all -> Runtime metric
89+ actualLog =
90+ this .getActualLog (operation , remoteService , remoteOperation , remoteResourceType , remoteResourceIdentifier );
91+ }
92+ }
93+ else {
8694 actualLog =
8795 this .getActualLog (operation , remoteService , remoteOperation , remoteResourceType , remoteResourceIdentifier );
8896 }
8997 }
90- else {
91- actualLog =
92- this .getActualLog (operation , remoteService , remoteOperation , remoteResourceType , remoteResourceIdentifier );
93- }
9498 log .info ("Value of an actual log: {}" , actualLog );
9599
96100 if (actualLog == null ) throw new BaseException (ExceptionCode .EXPECTED_LOG_NOT_FOUND );
@@ -147,6 +151,13 @@ private JsonifyArrayList<Map<String, Object>> getExpectedAttributes() throws Exc
147151 return flattenedJsonMapForExpectedLogArray ;
148152 }
149153
154+ private boolean isOtlpSigV4Log (Map <String , Object > expectedAttributes ) {
155+ // OTLP SigV4 logs have 'body' as a top-level attribute
156+ return expectedAttributes .containsKey ("body" ) &&
157+ expectedAttributes .containsKey ("severityNumber" ) &&
158+ expectedAttributes .containsKey ("severityText" );
159+ }
160+
150161 private Map <String , Object > getActualLog (
151162 String operation , String remoteService , String remoteOperation , String remoteResourceType , String remoteResourceIdentifier ) throws Exception {
152163 String dependencyFilter = null ;
@@ -223,6 +234,28 @@ private Map<String, Object> getActualOtelSpanLog(String operation, String remote
223234 return JsonFlattener .flattenAsMap (retrievedLogs .get (0 ).getMessage ());
224235 }
225236
237+ private Map <String , Object > getActualOtlpSigV4Log () throws Exception {
238+ // Filter pattern to match OTLP SigV4 logs
239+ String filterPattern = String .format (
240+ "{ ($.resource.attributes.[\" service.name\" ] = \" %s\" ) && $.body EXISTS && $.severityNumber EXISTS && $.severityText EXISTS }" ,
241+ context .getServiceName ()
242+ );
243+ log .info ("Filter Pattern for OTLP SigV4 Log Search: " + filterPattern );
244+
245+ List <FilteredLogEvent > retrievedLogs =
246+ this .cloudWatchService .filterLogs (
247+ context .getLogGroup (),
248+ filterPattern ,
249+ System .currentTimeMillis () - TimeUnit .MINUTES .toMillis (5 ),
250+ 10 );
251+
252+ if (retrievedLogs == null || retrievedLogs .isEmpty ()) {
253+ throw new BaseException (ExceptionCode .EMPTY_LIST );
254+ }
255+
256+ return JsonFlattener .flattenAsMap (retrievedLogs .get (0 ).getMessage ());
257+ }
258+
226259 @ Override
227260 public void init (
228261 Context context ,
0 commit comments