正则表达式拆分 Amazon S3 存储桶日志的列?

Posted

技术标签:

【中文标题】正则表达式拆分 Amazon S3 存储桶日志的列?【英文标题】:Regex to split columns of an Amazon S3 Bucket Log? 【发布时间】:2011-12-19 03:58:39 【问题描述】:

我正在为我公司的 S3 存储桶设置 ETL 流程,以便我们可以跟踪我们的使用情况,但我在拆分 S3 日志文件的列时遇到了一些麻烦,因为 Amazon 使用空格、双引号和正方形括号来分隔列。

我在这个 SO 帖子中找到了这个正则表达式:[^\\s\"']+|\"([^\"]*)\"|'([^']*)':Regex for splitting a string using space when not surrounded by single or double quotes,这让我非常接近。我只需要帮助调整它以忽略单引号并忽略“[”和“]”之间的空格

这是我们文件之一的示例行:

dd8d30dd085515d73b318a83f4946b26d49294a95030e4a7919de0ba6654c362 ourbucket.name.config [31/Oct/2011:17:00:04 +0000] 184.191.213.218 - 013259AC1A20DF37 REST.GET.OBJECT ourbucket.name.config.txt "GET /ourbucket.name.config.txt HTTP/1.1" 200 - 325 325 16 16 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" -

格式定义如下:http://s3browser.com/amazon-s3-bucket-logging-server-access-logs.php

任何帮助将不胜感激!

编辑:响应 FailDev,输出应该是包含在两个方括号之间的任何字符串,例如[foo bar],两个引号,例如“foo bar”或空格,例如foo bar(其中 foo 和 bar 都将单独匹配。我已将示例行中的每个匹配项都分解为以下块中自己的行:

dd8d30dd085515d73b318a83f4946b26d49294a95030e4a7919de0ba6654c362 
ourbucket.name.config 
[31/Oct/2011:17:00:04 +0000] 
184.191.213.218 
- 
013259AC1A20DF37 
REST.GET.OBJECT 
ourbucket.name.config.txt 
"GET /ourbucket.name.config.txt HTTP/1.1" 
200 
- 
325 
325 
16 
16 
"-" 
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" 
-

【问题讨论】:

输出到底应该是什么? 我不敢相信更多的人不需要这些信息!好问题,谢谢! 【参考方案1】:

这是我为解析节点中的 s3 日志文件而编写的一个愚蠢的正则表达式:

/^(.*?)\s(.*?)\s(\[.*?\])\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(\".*?\")\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(\".*?\")\s(\".*?\")\s(.*?)$/

正如我所说,这是“愚蠢的” - 它在很大程度上依赖于他们不更改日志格式,并且每个字段不包含任何奇怪的字符。

【讨论】:

【参考方案2】:

您不能使用 string.split 来完成,您需要遍历“列”组的所有捕获(如果您使用的是 C#)

This matches a non-quoted, non-bracketed field: [^\s\"\[\]]+
This matches a bracketed field: \[[^\]\[]+\] 
This matches a quoted field: \"[^\"]+\"

在匹配过程中保留引号和括号是最简单的,然后使用 Trim('[','\','"') 将它们去掉。

@"^((?<column>[^\s\"\[\]]+|\[[^\]\[]+\]|\"[^\"]+\")\s+)+$"

【讨论】:

谢谢,ORing 模式运行良好。此字符串模式最适合 C#:@"([^\s\""[]]+)|([[^][]+])|(\""[^\""]+\"") " 谢谢。似乎堆栈溢出删除了我的斜线......我忘了将它嵌入代码块中。现在更新。【参考方案3】:

这是一个 python 解决方案,可以帮助某人。它还会为您删除引号和方括号:

import re
log = '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be mybucket [06/Feb/2014:00:00:38 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be A1206F460EXAMPLE REST.GET.BUCKETPOLICY - "GET /mybucket?policy HTTP/1.1" 404 NoSuchBucketPolicy 297 - 38 - "-" "S3Console/0.4" -'

regex = '(?:"([^"]+)")|(?:\[([^\]]+)\])|([^ ]+)'

# Result is a list of triples, with only one having a value
# (due to the three group types: '""' or '[]' or '')
result = re.compile(regex).findall(log)
for a, b, c in result:
    print(a or b or c)

输出:

79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
mybucket
06/Feb/2014:00:00:38 +0000
192.0.2.3
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
A1206F460EXAMPLE
REST.GET.BUCKETPOLICY
-
GET /mybucket?policy HTTP/1.1
404
NoSuchBucketPolicy
297
-
38
-
-
S3Console/0.4
-
jon@jon-laptop:~/Downloads$ python regex.py
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
mybucket
06/Feb/2014:00:00:38 +0000
192.0.2.3
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
A1206F460EXAMPLE
REST.GET.BUCKETPOLICY
-
GET /mybucket?policy HTTP/1.1
404
NoSuchBucketPolicy
297
-
38
-
-
S3Console/0.4
-

【讨论】:

【参考方案4】:

我同意@andy!考虑到 S3 的访问日志已经存在了多长时间,我不敢相信有更多人没有处理 S3 的访问日志。


这是我使用的正则表达式

/(?:([a-z0-9]+)|-) (?:([a-z0-9\.-_]+)|-) (?:\[([^\]]+)\]|-) (?:([0-9\.]+)|-) (?:([a-z0-9]+)|-) (?:([a-z0-9.-_]+)|-) (?:([a-z\.]+)|-) (?:([a-z0-9\.-_\/]+)|-) (?:"-"|"([^"]+)"|-) (?:(\d+)|-) (?:([a-z]+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:"-"|"([^"]+)"|-) (?:"-"|"([^"]+)"|-) (?:([a-z0-9]+)|-)/i

如果你使用的是 node.js,你可以利用我的模块让这更容易处理,或者将它移植到 C#,基本的想法都在那里。

https://github.com/icodeforlove/s3-access-log-parser

【讨论】:

【参考方案5】:

我尝试在 C# 中使用它,但发现上面的答案中有一些不正确的字符,并且您必须在末尾使用非引号、非括号字段的正则表达式,否则它匹配所有内容(使用 http://regexstorm.net/tester) :

完整的正则表达式,首先是带括号的字段,第二个是带引号的字段,最后是不带引号的非括号字段:

一个简单的 C# 实现:

    MatchCollection matches = Regex.Matches(contents, @"(\[[^\]\[]+\])|(""[^""]+"")|([^\s""\[\]]+)");
    for (int i = 0; i < matches.Count; i++)
    
        Console.WriteLine(i + ": " + matches[i].ToString().Trim('[', ']', '"'));
    

【讨论】:

【参考方案6】:

这是我从AWS Knowledge Center 复制的正则表达式,并对其进行了一些修改以使其在 ASP.NET Core 中工作。

new Regex("([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)");

它对我们来说工作得很好。如果有人想使用c#类来存储访问日志,下面是解析日志文件的每一行并为其创建S3ServerAccessLog对象的代码。

private List<S3ServerAccessLog> ParseLogs(string accessLogs)

    // split log file per new line since each log will be on a single line.
    var splittedLogs = accessLogs.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
    var parsedLogs = new List<S3ServerAccessLog>();

    foreach (var logLine in splittedLogs)
    
        var parsedLog = ACCESS_LOG_REGEX.Split(logLine).Where(s => s.Length > 0).ToList();
                
        // construct 
        var logModel = new S3ServerAccessLog
        
            BucketOwner = parsedLog[0],
            BucketName = parsedLog[1],
            RequestDateTime = DateTimeOffset.ParseExact(parsedLog[2], "dd/MMM/yyyy:HH:mm:ss K", CultureInfo.InvariantCulture),
            RemoteIP = parsedLog[3],
            Requester = parsedLog[4],
            RequestId = parsedLog[5],
            Operation = parsedLog[6],
            Key = parsedLog[7],
            RequestUri = parsedLog[8].Replace("\"", ""),
            HttpStatus = int.Parse(parsedLog[9]),
            ErrorCode = parsedLog[10],
            BytesSent = parsedLog[11],
            ObjectSize = parsedLog[12],
            TotalTime = parsedLog[13],
            TurnAroundTime = parsedLog[14],
            Referrer = parsedLog[15].Replace("\"", ""),
            UserAgent = parsedLog[16].Replace("\"", ""),
            VersionId = parsedLog[17],
            HostId = parsedLog[18],
            Sigv = parsedLog[19],
            CipherSuite = parsedLog[20],
            AuthType = parsedLog[21],
            EndPoint = parsedLog[22],
            TlsVersion = parsedLog[23]
        ;

        parsedLogs.Add(logModel);
    

    return parsedLogs;

【讨论】:

以上是关于正则表达式拆分 Amazon S3 存储桶日志的列?的主要内容,如果未能解决你的问题,请参考以下文章

如何将日志从 Amazon S3 存储桶导入到 cloudwatch

Amazon AWS Athena S3 和 Glacier 混合存储桶

json 列出所有Amazon S3存储桶并允许管理单个存储桶。

访问 Amazon S3 公共存储桶

向 Amazon S3 存储桶授予权限

访问我在 Amazon 中的 S3 存储桶