正则表达式拆分 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 混合存储桶