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

问题描述 投票:10回答:3

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

amazon-web-services amazon-cloudwatch amazon-cloudwatchlogs
3个回答
16
投票

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

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

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

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"
}

要为特定日志组查找相同内容,可以更改命令以适应以下维度:

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 level 6压缩进行压缩。因此,存储字节是指Cloudwatch在摄取日志后用于存储日志的存储空间。

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


4
投票

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

您可以结合使用AWS CLI工具,csvfix CSV软件包和电子表格来完成此任务。

  • 登录AWS Cloudwatch控制台并获取已生成所有数据的日志组的名称。在我的情况下,它被称为“test01-ecs”。
  • 不幸的是,在Cloudwatch控制台中,您无法通过“存储的字节”(它会告诉您哪些是最大的)对流进行排序。如果日志组中有太多的流要在控制台中查看,那么您需要以某种方式转储它们。为此,您可以使用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文件,可以轻松导入到电子表格中,确保定义用于导入的logStreams键: $ in2csv cloudwatch-output.json --key logStreams >> ./cloudwatch-output.csv
  • 将生成的CSV文件导入电子表格(我自己使用LibreOffice,因为它似乎非常适合处理CSV)确保将storedBytes字段导入为整数。
  • 对电子表格中的storedBytes列进行排序,以确定哪个或哪些日志流生成的数据最多。

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


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))
        
© www.soinside.com 2019 - 2024. All rights reserved.