11

I would like to get Cloudwatch screenshot automatically since I have many instances.

But when I try to run get-metric-widget-image by aws cli command tool, I always get error.

An error occurred (ValidationError) when calling the GetMetricWidgetImage operation: MetricWidget property 'metricWidget' has a bad JSON content.

Is there anyone who could help me out? Thanks.

I could not find an example from aws doc. No exact example in below link. https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Metric-Widget-Structure.html

My command is like this.

aws cloudwatch get-metric-widget-image  --metric-widget "{ "width":600,"height":395,"metrics":[["AWS/EC2","CPUUtilization","InstanceId","i-01234567890123456",{"stat":"Average"}]],"period":300,"start":"-P30D","end":"PT0H","stacked":false,"yAxis":{"left":{"min":0.1,"max":1},"right":{"min":0}},"title":"CPU","annotations":{"horizontal":[{"color":"#ff6961","label":"Troublethresholdstart","fill":"above","value":0.5}], "vertical":[{"visible":true, "color":"#9467bd","label":"Bugfixdeployed","value":"2018-11-19T07:25:26Z","fill":"after"}]}}}" --output-format "png" 
atline
  • 28,355
  • 16
  • 77
  • 113
ingsnow kwan
  • 113
  • 1
  • 5

4 Answers4

18

The best way to get the correct json for your request is to use CloudWatch Console to construct the graph, then click on the Source tab, select Image API view and click Copy Source to copy the json generated there. You also need to wrap the json in single quotes, like this:

aws cloudwatch get-metric-widget-image --metric-widget \
'{
    "width": 600,
    "height": 395,
    "metrics": [
        [ "AWS/EC2", "CPUUtilization", "InstanceId", "i-01234567890123456", { "stat": "Average" } ]
    ],
    "period": 300,
    "stacked": false,
    "yAxis": {
        "left": {
            "min": 0.1,
            "max": 1
        },
        "right": {
            "min": 0
        }
    },
    "title": "CPU",
    "annotations": {
        "horizontal": [
            {
                "color": "#ff6961",
                "label": "Troublethresholdstart",
                "fill": "above",
                "value": 0.5
            }
        ],
        "vertical": [
            {
                "visible": true,
                "color": "#9467bd",
                "label": "Bugfixdeployed",
                "value": "2018-11-19T07:25:26Z",
                "fill": "after"
            }
        ]
    },
    "view": "timeSeries"
}'

Response to this will be a base64 encoded image, like this:

{
    "MetricWidgetImage": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAGLEAYA..."
}

If you need the raw png image, you'll need to decode the response by doing something like this:

aws cloudwatch get-metric-widget-image --metric-widget 'JSON_GOES_HERE' | grep MetricWidgetImage | awk '{split($0,a,"\""); print a[4]}' | base64 --decode > graph.png
Dejan Peretin
  • 10,891
  • 1
  • 45
  • 54
  • Thank you so much,Tartaglia! Very detailed answer. I am a green hand at AWS. It works for me and I could get the correct picture. – ingsnow kwan Nov 20 '18 at 09:13
  • 2
    Even easier with JQ Use `jq -r` for raw output (removes quotes from string); Assuming image request is in `request.json` file (can always inline it too); `aws cloudwatch get-metric-widget-image --metric-widget file://request.json --output-format png | jq -r '.MetricWidgetImage' | base64 --decode >| image.png` – mhoglan Mar 31 '19 at 22:54
  • 1
    jq is unneeded, and default format is always png (it's actually the only option right now). You can `aws cloudwatch get-metric-widget-image --metric-widget file://request.json --query 'MetricWidgetImage' --output text | base64 -d > image.png` – madeddie Jan 13 '20 at 16:44
  • This post and answer are life / time savers! Any idea how to integrate this with Slack? – Kwhitejr Jun 25 '20 at 19:22
  • Also, @madeddie your script worked perfectly except that I required `... base64 -D ...` i.e. capital D not lowercase d – Kwhitejr Jun 25 '20 at 20:39
  • 1
    @Kwhitejr, right, that depends on your OS, linux uses -d, I think that might be a GNUism, MacOS allows for both lately, but some BSDs and older MacOS want capital -D. – madeddie Jul 02 '20 at 18:32
4

Here is a script I use to download images for the same metric for each day. The script shows how to invoke aws cloudwatch get-metric-widget-image with variable arguments and to convert output to a png file.

function getDbDailyMetricImage
{
    local date=$1
    local dbId=$2
    local metric=${3:-'CPUUtilization'}
    local metricMin=$4
    local metricMax=$5

    local dateF=$(date --date="$date" +%F)
    local start="${dateF}T00:00:00.000Z"
    local end="${dateF}T23:59:59.999Z"

    echo "Downloading image for $dbId $metric [$metricMin .. $metricMax]" \
         "and Time [$start .. $end]"
    aws --region us-east-1 cloudwatch get-metric-widget-image --metric-widget \
        '{
          "metrics": [
              [ "AWS/RDS", "'$metric'", "DBInstanceIdentifier", "'$dbId'", 
                { "period": 300, "yAxis": "left" } ]
          ],
          "yAxis": {
             "left": {
                 "min": '$metricMin',
                 "max": '$metricMax'
             }
          },
          "title": "'"$dateF $metric of $dbId vs Time UTC"'",
          "legend": {
             "position": "hidden"
          },
          "view": "timeSeries",
          "stacked": true,
          "period": 300,
          "width": 1200,
          "height": 800,
          "start": "'$start'",
          "end": "'$end'"
        }' \
        --output-format png --output text | base64 --decode > $metric-$dbId-$dateF.png
}

for daysAgo in {0..30}
do
    getDbDailyMetricImage $(date --date="$daysAgo days ago" +%F) mydb1 CPUUtilization 0 100
    getDbDailyMetricImage $(date --date="$daysAgo days ago" +%F) mydb1 ReadIOPS 0 10000
done

another useful analytic tool I use it to combine all or some of the graphs into one using ImageMagick convert -compose Multiply. For example,

convert ReadIOPS-mydb1-2019-0*.png -compose Multiply -layers flatten ReadIOPS-mydb1-2019-composite.png
Nicholas Sushkin
  • 13,050
  • 3
  • 30
  • 20
2

JSONLint says that you've got one extra } at the end of your JSON. Also, try wrapping the whole JSON block with single quotes ' for easier differentiating and no need to escape the double quotes in the JSON string.

This should work for you:

aws cloudwatch get-metric-widget-image --metric-widget '{ "width":600,"height":395,"metrics":[["AWS/EC2","CPUUtilization","InstanceId","i-01234567890123456",{"stat":"Average"}]],"period":300,"start":"-P30D","end":"PT0H","stacked":false,"yAxis":{"left":{"min":0.1,"max":1},"right":{"min":0}},"title":"CPU","annotations":{"horizontal":[{"color":"#ff6961","label":"Troublethresholdstart","fill":"above","value":0.5}], "vertical":[{"visible":true, "color":"#9467bd","label":"Bugfixdeployed","value":"2018-11-19T07:25:26Z","fill":"after"}]}}' --output-format "png"
Gabe Hollombe
  • 7,847
  • 4
  • 39
  • 44
1

Here's a different answer. Within https://github.com/kcrossen/CloudWatch_Remote_Monitor/blob/master/Source_Code/ there is a Python script that will digest your dashboard source code mentioned by Tartaglia above and generate the proper json parameters for GetMetricWidgetImage. There's also a Kivy script to display the PNG images returned.

kcrossen
  • 159
  • 2
  • 4