Parse a CloudWatch alert in AWS Lambda Python function - python-3.x

I'm working on Lambda function that will perform several actions based on CloudWatch alerts.
The JSON format of the alerts is:
{
'SignatureVersion': '1',
'Timestamp': '2018-03-08T16: 06: 27.163Z',
'MessageId': 'df82d564-1651-5dc6-a37a-867f779226ec',
'Message': '{
"AlarmName": "awsec2-i-08c38bb8af7962797-CPU-Utilization",
"AlarmDescription": "Created from EC2 Console",
"AWSAccountId": "111111111111",
"NewStateValue": "ALARM",
"NewStateReason": "Threshold Crossed: 1 datapoint [1.49999999999939 (08/03/18 16:04:00)] was greater than or equal to the threshold (1.0).",
"StateChangeTime": "2018-03-08T16:06:27.124+0000",
"Region": "EU (Ireland)",
"OldStateValue": "OK",
"Trigger": {
"MetricName": "CPUUtilization",
"Namespace": "AWS/EC2",
"StatisticType": "Statistic",
"Statistic": "AVERAGE",
"Unit": null,
"Dimensions": [
{
"name": "InstanceId",
"value": "i-08c38bb8af7962797"
}
],
"Period": 60,
"EvaluationPeriods": 1,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"Threshold": 1.0,
"TreatMissingData": "",
"EvaluateLowSampleCountPercentile": ""
}
}',
'Type': 'Notification',
'TopicArn': 'arn:aws:sns:eu-west-1: 11111111111:test',
'Subject': 'ALARM: "awsec2-i-08c38bb8af7962797-CPU-Utilization" in EU (Ireland)'
}
What I need to understand is how I tell my function to extract only the InstanceId value and use it as variable for the rest of the function.

The Message is JSON provided as a string. To access the contents of the string, you'll need to use the json.loads() function:
import json
alert = ... (from CloudWatch)
message = json.loads(alert['Message'])
[msg['value'] for msg in message['Trigger']['Dimensions'] if msg['name']=='InstanceId']
However, please note that this will merely output the InstanceId that was provided as the Dimension for the alarm. It is not specifically saying that this instance caused the alarm (but that is true).
For example, you could create an alarm based on a group of EC2 instances. If the average CPU went above a threshold, the alarm would be triggered. However, the dimension would relate to the group, not a specific instance.
Think of it as saying "The Alarm with a filter of Instance i-xxx has been triggered", as opposed to saying "Instance i-xxx triggered the alarm".
As long as your alarm is always based on a single instance, then the Dimension will be what you expect.

Related

AWS Lex V2 - DailogHook Validation

Does anyone know how I check what slot I am processing if I do some validation at the slot level? As I have looked at the event payload and there seems to be no reference to the slot you are calling your Lambda function on.
At present the Lex event passed to Lambda functions does not contain any hint as to which slot is presently being ellicted.
However, looking at the slots array in the event, you can determine when to validate based on the current value.
Values that have not yet been elicited are null; whereas values that have been ascertained from the user have a non-null value.
You can validate the non-nulls and assuming you handle the scenarios correctly you should be fine. By that I mean if the value fails validation you will need to issue an ElicitSlot prompt for the same slot; potentially with a useful error message. If the value passes validation you can issue a Delegate response and allow Lex to continue processing accordingly.
Below is a sample event received by my Lambda function for a V2 Lex bot:
"intent": {
"slots": {
"duration": null,
"reason": null,
"quantity": {
"shape": "Scalar",
"value": {
"originalValue": "2",
"resolvedValues": [
"2"
],
"interpretedValue": "2"
}
}
},
"confirmationState": "None",
"name": "MainIntent",
"state": "InProgress"
},
In my example, MainIntent has three slots but only one has a value. My Lambda function will validate the non-nulls and then delegate to Lex for the rest of the processing.

Hopping Window in Azure Stream Analytics

I try to get my head around the hopping window in azure stream analytics.
I'll get the following data from an Azure Event Hub:
[
{
"Id": "1",
"SensorData": [
{
"Timestamp": 1603112431,
"Type": "LineCrossing",
"Direction": "forward"
},
{
"Timestamp": 1603112431,
"Type": "LineCrossing",
"Direction": "forward"
}
],
"EventProcessedUtcTime": "2020-10-20T06:35:48.5890814Z",
"PartitionId": 1,
"EventEnqueuedUtcTime": "2020-10-20T06:35:48.3540000Z"
},
{
"Id": "1",
"SensorData": [
{
"Timestamp": 1603112430,
"Type": "LineCrossing",
"Direction": "backward"
}
],
"EventProcessedUtcTime": "2020-10-20T06:35:48.5890814Z",
"PartitionId": 0,
"EventEnqueuedUtcTime": "2020-10-20T06:35:48.2140000Z"
}
]
My query looks like the following:
SELECT s.Id, COUNT(data.ArrayValue.Direction) as Count
FROM [customers] s TIMESTAMP BY EventEnqueuedUtcTime
CROSS APPLY GetArrayElements(s.SensorData) AS data
WHERE data.ArrayValue.Type = 'LineCrossing'
AND data.ArrayValue.Direction = 'forward'
GROUP BY s.Id, HoppingWindow(second, 3600, 5)
I used a Hopping Window to get every 5th second all events from the last day.
My expectation for the given dto would be: One row with Id1 and Count 2, but what I receive is: 720 rows (so 3600 divided by 5) with Id1 has Count 2.
Shouldn't those events not be aggregated by the HoppingWindow function?
I structured your query as it follows:
with inputValues as (Select input.*, message.ArrayValue as Data from input CROSS APPLY GetArrayElements(input.SensorData) as message)
select inputValues.Id, count(Data.Direction) as Count
into output
from inputValues
where Data.Type = 'LineCrossing' and Data.Direction='forward'
GROUP BY inputValues.Id, HoppingWindow(second, 3600, 5)
I have set the input to Event Hub, and in the Visual Studio I have started a query with the cloud input.
I used a Windows Client application to pipe in the messages to Event Hub(2. from the picture below) and observed that events were coming every 5 seconds(1. from the picture below and 3. from the picture below).
Maybe just change the query I shared to reflect the correct time-stamping, but the result should be as expected - every 5 seconds count to the output per the defined condition for all events that arrived in the last hour(3600 seconds in the HoppingWindow function).

Stripe Orders API tax callback

Trying to setup dynamic tax calcuation using Stripe Orders API. Using these docs:
https://stripe.com/docs/orders
https://stripe.com/docs/orders/dynamic-shipping-taxes
result = {
"order_update": {
"items": [
{
"parent": None,
"type": "tax",
"description": "Sales taxes",
"amount": 100,
"currency": "usd"
}
],
"shipping_methods": [
{
"id": "free_shipping",
"description": "Free 7-day shipping",
"amount": 0,
"currency": "usd",
"delivery_estimate": {
"type": "exact",
"date": "2020-08-11"
},
"tax_items": []
}
]
}
}
print(result)
return Response(result, status=status.HTTP_200_OK)
Even dummy response without any sophisticated computations failed to create an order object with HTTP 402 error for script trying to create Order
Creating order with no tax specified works as well and allows to create order.
Webservice running a callback receives a request from the Stripe as it must and works as well.
Stripe support says only "we no longer recommend developing your integration around this system" and does not answer directy if they turn off this feature.
If they turn off this feature I do not understand why it is available in the dashboard.
The issue was in the middleware of my service. It transformed response keys from snake_case to camelCase. Resolved.

Azure Maps API - Limit By Type

I have implemented the Azure Maps search at https://learn.microsoft.com/en-gb/rest/api/maps/search/getsearchaddress but I want to get a list of only certain "types".
In the results below, the type is "Street", but I am interested in returning only those where the type matches "MunicipalitySubdivision".
If I do a call to this service, the API returns results in blocks of 10 by default (which can be upped to 200), and gives a TotalResults field as well. It is possible to iterate through (for example) 50,000 results 200 at a time by providing a results offset startIndex parameter in the API, but this doesn't seem like the most efficient way to return just results of one type.
Can anyone suggest anything?
{
"type": "Street",
"id": "GB/STR/p0/1199538",
"score": 5.07232,
"address": {
"streetName": "Hampton Road",
"municipalitySubdivision": "Birmingham, Aston",
"municipality": "Birmingham",
"countrySecondarySubdivision": "West Midlands",
"countrySubdivision": "ENG",
"postalCode": "B6",
"extendedPostalCode": "B6 6AB,B6 6AE,B6 6AN,B6 6AS",
"countryCode": "GB",
"country": "United Kingdom",
"countryCodeISO3": "GBR",
"freeformAddress": "Hampton Road, Birmingham",
"countrySubdivisionName": "England"
},
"position": {
"lat": 52.50665,
"lon": -1.90082
},
"viewport": {
"topLeftPoint": {
"lat": 52.50508,
"lon": -1.90015
},
"btmRightPoint": {
"lat": 52.50804,
"lon": -1.90139
}
}
}
There currently isn't an option to limit the results as you requested other than to scan the results programmatically. If the address information you have is structured (you have the individual pieces) and is not a freeform string, then using the structured geocoding service would allow you to specify the type right request when passing in the address parts: https://learn.microsoft.com/en-us/rest/api/maps/search/getsearchaddressstructured

Request telemetry - "durationMetric"?

When parsing exported Application Insights telemetry from Blob storage, the request data looks something like this:
{
"request": [
{
"id": "3Pc0MZMBJgQ=",
"name": "POST Blah",
"count": 6,
"responseCode": 201,
"success": true,
"url": "https://example.com/api/blah",
"durationMetric": {
"value": 66359508.0,
"count": 6.0,
"min": 11059918.0,
"max": 11059918.0,
"stdDev": 0.0,
"sampledValue": 11059918.0
},
...
}
],
...
}
I am looking for the duration of the request, but I see that I am presented with a durationMetric object.
According to the documentation the request[0].durationMetric.value field is described as
Time from request arriving to response. 1e7 == 1s
But if I query this using Analytics, the value don't match up to this field:
They do, however, match up to the min, max and sampledValue fields.
Which field should I use? And what does that "value": 66359508.0 value represent in the above example?
It doesn't match because you're seeing sampled data (meaning this event represents sampled data from multiple requests). I'd recommend starting with https://azure.microsoft.com/en-us/documentation/articles/app-insights-sampling/ to understand how sampling works.
In this case, the "matching" value would come from duration.sampledValue (notice that value == count * sampledValue)
It's hard to compare exactly what you're seeing because you don't show the Kusto query you're using, but you do need to be aware of sampling when writing AI Analytics queries. See https://azure.microsoft.com/en-us/documentation/articles/app-insights-analytics-tour/#counting-sampled-data for more details on the latter.

Resources