我的AWS Cloudwatch账单非常庞大。我如何确定导致它的日志流?

时间:2017-04-10 15:50:16

标签: amazon-web-services amazon-cloudwatch amazon-cloudwatchlogs

我上个月从亚马逊购买了一张价值1,200美元的Cloudwatch服务发票(特别是在“AmazonCloudWatch PutLogEvents”中提取了2 TB的日志数据),当时我预计会花几十美元。我已登录AWS控制台的Cloudwatch部分,可以看到我的一个日志组使用了大约2TB的数据,但该日志组中有数千个不同的日志流,如何判断哪个使用了该数量数据?

5 个答案:

答案 0 :(得分:16)

在CloudWatch控制台上,使用IncomingBytes指标使用“指标”页面以未压缩字节的形式查找特定时间段内每个日志组摄取的数据量。请按照以下步骤-

  1. 转到CloudWatch指标页面,然后单击AWS名称空间“日志”->“日志组指标”。
  2. 选择所需日志组的IncomingBytes指标,然后单击“图形指标”选项卡以查看该图。
  3. 更改开始时间和结束时间,以使它们之间的差值为30天,并将时间段更改为30天。这样,我们将仅获得一个数据点。还将图形更改为数字,将统计信息更改为总和。

这样,您将看到每个日志组提取的数据量,并了解哪个日志组正在提取多少数据。

enter image description here

您还可以使用AWS CLI获得相同的结果。例如,您只想知道日志组在30天内摄取的数据总量的示例场景,则可以使用get-metric-statistics CLI命令-

示例CLI命令-

aws cloudwatch get-metric-statistics --metric-name IncomingBytes --start-time 2018-05-01T00:00:00Z --end-time 2018-05-30T23:59:59Z --period 2592000 --namespace AWS/Logs --statistics Sum --region us-east-1

样本输出-

{
    "Datapoints": [
        {
            "Timestamp": "2018-05-01T00:00:00Z", 
            "Sum": 1686361672.0, 
            "Unit": "Bytes"
        }
    ], 
    "Label": "IncomingBytes"
}

要为特定的日志组找到相同的内容,可以更改命令以适应--p这样的尺寸

aws cloudwatch get-metric-statistics --metric-name IncomingBytes --start-time 2018-05-01T00:00:00Z --end-time 2018-05-30T23:59:59Z --period 2592000 --namespace AWS/Logs --statistics Sum --region us-east-1 --dimensions Name=LogGroupName,Value=test1

您可以在所有日志组上逐个运行此命令,并检查哪个日志组负责大部分数据摄取账单并采取纠正措施。

  

注意:更改特定于您的环境和要求的参数。

OP提供的解决方案提供的数据存储量与摄取的日志不同。

有什么区别?

每月摄取的数据与数据存储字节不同。将数据提取到CloudWatch之后,它由CloudWatch存档,其中每个日志事件包含26字节的元数据,并使用gzip 6级压缩对其进行压缩。因此,存储字节是指Cloudwatch在提取日志后用于存储日志的存储空间。

参考:https://docs.aws.amazon.com/cli/latest/reference/cloudwatch/get-metric-statistics.html

答案 1 :(得分:7)

尽管问题的作者和其他人以很好的方式回答了该问题,但我将尝试找到一种通用的解决方案,该解决方案可以在不知道确切的日志组名称的情况下使用造成太多的日志。

为此,我们不能使用描述日志流功能,因为这需要-log-group-name 如我之前所说,我不知道我的日志组名称的值。

我们可以使用描述日志组功能,因为该功能不需要任何参数。

请注意,我假设您已在〜/ .aws / config 文件中配置了所需的标志(--region),并且您的EC2实例具有所需的权限执行此命令。

aws logs describe-log-groups

此命令将列出您aws帐户中的所有日志组。样本输出为

 {
    "logGroups": [
        {
            "metricFilterCount": 0,
            "storedBytes": 62299573,
            "arn": "arn:aws:logs:ap-southeast-1:855368385138:log-group:RDSOSMetrics:*",
            "retentionInDays": 30,
            "creationTime": 1566472016743,
            "logGroupName": "/aws/lambda/us-east-1.test"
        }
    ]
}

如果您只对日志组的特定前缀模式感兴趣,则可以使用-log-group-name-prefix 这样的

aws logs describe-log-groups --log-group-name-prefix /aws/lambda

此命令的输出JSON也将与上面的输出类似。

如果您的帐户中的日志组太多,则很难分析其输出,并且我们需要一些命令行实用工具来简要了解结果。 我们将使用“ jq ”命令行实用程序来获取所需的内容。目的是获取哪个日志组产生的日志量最多,从而导致更多的钱

根据输出JSON,我们需要进行分析的字段将为“ logGroupName”和“ storedBytes”。因此,请在“ jq”命令中使用这两个字段。

aws logs describe-log-groups --log-group-name-prefix /aws/ 
| jq -M -r '.logGroups[] | "{\"logGroupName\":\"\(.logGroupName)\",
\"storedBytes\":\(.storedBytes)}"'

在命令中使用'\'进行转义,因为我们希望输出使用JSON的 sort_by 函数,并且仅 为JSON格式。示例输出如下:

{"logGroupName":"/aws/lambda/test1","storedBytes":3045647212}
{"logGroupName":"/aws/lambda/projectTest","storedBytes":200165401}
{"logGroupName":"/aws/lambda/projectTest2","storedBytes":200}

请注意,输出结果将不会按storedBytes排序,因此我们希望对它们进行排序,以获取哪个日志组是最有问题的日志组。

我们将使用jq的 sort_by 函数来完成此操作。样本命令就是这样

aws logs describe-log-groups --log-group-name-prefix /aws/ 
| jq -M -r '.logGroups[] | "{\"logGroupName\":\"\(.logGroupName)\",
\"storedBytes\":\(.storedBytes)}"' 
|  jq -s -c 'sort_by(.storedBytes) | .[]'

对于上面的示例输出,这将产生以下结果

{"logGroupName":"/aws/lambda/projectTest2","storedBytes":200}
{"logGroupName":"/aws/lambda/projectTest","storedBytes":200165401}
{"logGroupName":"/aws/lambda/test1","storedBytes":3045647212}

此列表底部的元素是与之关联的日志最多的元素。您可以将过期事件属性设置为有限时间,例如将这些日志组设置为1个月。

如果您想知道所有日志字节的总和是多少,则可以使用jq的“ map”和“ add”功能,如下所示。

 aws logs describe-log-groups --log-group-name-prefix /aws/ 
        | jq -M -r '.logGroups[] | "{\"logGroupName\":\"\(.logGroupName)\",
\"storedBytes\":\(.storedBytes)}"'
        |  jq -s -c 'sort_by(.storedBytes) | .[]' 
        | jq -s 'map(.storedBytes) | add '

对于上面的示例输出,此命令的输出为

3245812813

答案已经很冗长,但我希望它有助于找出cloudwatch中最有问题的日志组。

答案 2 :(得分:4)

好的,我answering my own question在这里,但我们走了(欢迎所有其他答案):

您可以结合使用AWS CLI工具,csvfix CSV软件包和电子表格来解决这个问题。

  • 登录AWS Cloudwatch控制台并获取已生成所有数据的日志组的名称。就我而言,它被称为" test01-ecs"。
  • 不幸的是,在Cloudwatch控制台中,您无法通过" Stored Bytes"对流进行排序。 (这会告诉你哪些是最大的)。如果日志组中有太多的流要在控制台中查看,那么您需要以某种方式转储它们。为此,您可以使用AWS CLI工具:

    $ aws logs describe-log-streams --log-group-name test01-ecs

  • 上面的命令将为您提供JSON输出(假设您的AWS CLI工具设置为JSON输出 - 如果没有,则将其设置为output = json中的~/.aws/config),它将看起来像这样:

    { "logStreams": [ { "creationTime": 1479218045690, "arn": "arn:aws:logs:eu-west-1:902720333704:log-group:test01-ecs:log-stream:test-spec/test-spec/0307d251-7764-459e-a68c-da47c3d9ecd9", "logStreamName": "test-spec/test-spec/0308d251-7764-4d9f-b68d-da47c3e9ebd8", "storedBytes": 7032 } ] }

  • 将此输出传递给JSON文件 - 在我的情况下,文件大小为31 MB:

    $ aws logs describe-log-streams --log-group-name test01-ecs >> ./cloudwatch-output.json

  • 使用 in2csv 包(csvfix的一部分)将JSON文件转换为CSV文件,可以轻松导入电子表格,确保定义<用于导入的em> logStreams 键:

    $ in2csv cloudwatch-output.json --key logStreams >> ./cloudwatch-output.csv

  • 将生成的CSV文件导入电子表格(我自己使用LibreOffice,因为它似乎非常适合处理CSV)确保 storedBytes 字段作为整数导入。

  • 对电子表格中的 storedBytes 列进行排序,以确定哪些日志流生成的数据最多。

在我的情况下,这工作 - 结果我的一个日志流(来自redis实例中来自破坏的TCP管道的日志)是所有其他流组合的大小的4,000倍!

答案 3 :(得分:4)

由于意外检入,我们有lambda记录了GB的数据。这是一个基于boto3的python脚本,基于上述答案中的信息,该脚本可扫描所有日志组并在过去7天中打印出日志大于1GB的任何组。这比尝试使用更新缓慢的AWS仪表板对我有更多帮助。

#!/usr/bin/env python3

# Outputs all loggroups with > 1GB of incomingBytes in the past 7 days

import boto3
from datetime import datetime as dt
from datetime import timedelta


logs_client = boto3.client('logs')
cloudwatch_client = boto3.client('cloudwatch')

end_date = dt.today().isoformat(timespec='seconds')
start_date = (dt.today() - timedelta(days=7)).isoformat(timespec='seconds')
print("looking from %s to %s" % (start_date, end_date))

paginator = logs_client.get_paginator('describe_log_groups')
pages = paginator.paginate()
for page in pages:
     for json_data in page['logGroups']:
        log_group_name = json_data.get("logGroupName") 

        cw_response = cloudwatch_client.get_metric_statistics(
           Namespace='AWS/Logs',    
           MetricName='IncomingBytes',
           Dimensions=[
            {
                'Name': 'LogGroupName',
                'Value': log_group_name
            },
            ],
            StartTime= start_date,
            EndTime=end_date,
            Period=3600 * 24 * 7,
            Statistics=[
                'Sum'
            ],
            Unit='Bytes'
        )
        if len(cw_response.get("Datapoints")):
            stats_data = cw_response.get("Datapoints")[0]
            stats_sum = stats_data.get("Sum")   
            sum_GB = stats_sum /  (1000 * 1000 * 1000)
            if sum_GB > 1.0:
                print("%s = %.2f GB" % (log_group_name , sum_GB))
        

答案 4 :(得分:1)

您还可以单击cloudwatch日志仪表板上的齿轮上的齿轮,然后选择存储的字节列。

我还单击了“永不过期”的内容,并将日志更改为过期。

Use cloudwatch logs gear and select "Stored Bytes" column