有没有办法为 CloudWatch 日志组过滤器生成 AWS 控制台 URL?

Ric*_*urt 14 amazon-web-services amazon-cloudwatch aws-cloudwatch-log-insights

我想将我的用户直接发送到特定的日志组和过滤器,但我需要能够生成正确的 URL 格式。例如,这个网址

https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/
%252Fmy%252Flog%252Fgroup%252Fgoes%252Fhere/log-events/$3FfilterPattern$3D$255Bincoming_ip$252C$2Buser_name$252C$2Buser_ip$2B$252C$2Btimestamp$252C$2Brequest$2B$2521$253D$2B$2522GET$2B$252Fhealth_checks$252Fall$2B*$2522$252C$2Bstatus_code$2B$253D$2B5*$2B$257C$257C$2Bstatus_code$2B$253D$2B429$252C$2Bbytes$252C$2Burl$252C$2Buser_agent$255D$26start$3D-172800000
Run Code Online (Sandbox Code Playgroud)

将带您到一个名为的日志组,/my/log/group/goes/here并使用此模式过滤过去 2 天的消息:

[incoming_ip, user_name, user_ip , timestamp, request != "GET /health_checks/all *", status_code = 5* || status_code = 429, bytes, url, user_agent]
Run Code Online (Sandbox Code Playgroud)

我可以解码 URL 的一部分,但我不知道其他一些字符应该是什么(见下文),但这对我来说看起来并不像任何标准的 HTML 编码。有人知道这种 URL 格式的编码器/解码器吗?

%252F == /
$252C == ,
$255B == [
$255D == ]
$253D == =
$2521 == !
$2522 == "
$252F == _
$257C == |

$2B == +
$26 == &
$3D == =
$3F == ?
Run Code Online (Sandbox Code Playgroud)

小智 18

首先我要感谢其他人提供的线索。进一步完整解释了如何构建 Log Insights 链接。

总的来说,它只是一个对象结构的奇怪编码结合,其工作原理如下:

  • 之后的部分?queryDetail=是对象表示,并{}表示为~()

  • 对象被遍历到原始值,后者被转换如下:

    • encodeURIComponent(value)以便所有特殊字符都转换为%xx
    • replace(/%/g, "*")这样这个编码就不会受到顶级编码的影响
    • 如果值类型是string- 它以不匹配的单引号作为前缀

    为了显示:

    "Hello world" -> "Hello%20world" -> "Hello*20world" -> "'Hello*20world"
    
    Run Code Online (Sandbox Code Playgroud)
  • 转换后的基元数组使用~并放入~()构造内部

然后,在完成基元转换后 - 使用“~”连接对象。

该字符串之后是escape()d (请注意,encodeURIComponent()调用 not 是因为它在 JS 中不进行转换~)。

之后?queryDetail=添加。

最后,这个字符串被我们encodeURIComponent()ed 和作为顶部的樱桃 -%替换为$

让我们看看它在实践中是如何运作的。假设这些是我们的查询参数:

"Hello world" -> "Hello%20world" -> "Hello*20world" -> "'Hello*20world"
Run Code Online (Sandbox Code Playgroud)

首先对原语进行变换:

const expression = `fields @timestamp, @message
    | filter @message not like 'example'
    | sort @timestamp asc
    | limit 100`;

const logGroups = ["/application/sample1", "/application/sample2"];

const queryParameters = {
  end: 0,
  start: -3600,
  timeType: "RELATIVE",
  unit: "seconds",
  editorString: expression,
  isLiveTrail: false,
  source: logGroups,
};

Run Code Online (Sandbox Code Playgroud)

然后,使用连接对象~,因此我们有对象表示字符串:

const expression = "'fields*20*40timestamp*2C*20*40message*0A*20*20*20*20*7C*20filter*20*40message*20not*20like*20'example'*0A*20*20*20*20*7C*20sort*20*40timestamp*20asc*0A*20*20*20*20*7C*20limit*20100";

const logGroups = ["'*2Fapplication*2Fsample1", "'*2Fapplication*2Fsample2"];

const queryParameters = {
  end: 0,
  start: -3600,
  timeType: "'RELATIVE",
  unit: "'seconds",
  editorString: expression,
  isLiveTrail: false,
  source: logGroups,
};

Run Code Online (Sandbox Code Playgroud)

现在我们escape()

const objectString = "~(end~0~start~-3600~timeType~'RELATIVE~unit~'seconds~editorString~'fields*20*40timestamp*2C*20*40message*0A*20*20*20*20*7C*20filter*20*40message*20not*20like*20'example'*0A*20*20*20*20*7C*20sort*20*40timestamp*20asc*0A*20*20*20*20*7C*20limit*20100~isLiveTrail~false~source~(~'*2Fapplication*2Fsample1~'*2Fapplication*2Fsample2))"
Run Code Online (Sandbox Code Playgroud)

现在我们添加?queryDetail=前缀:

const escapedObject = "%7E%28end%7E0%7Estart%7E-3600%7EtimeType%7E%27RELATIVE%7Eunit%7E%27seconds%7EeditorString%7E%27fields*20*40timestamp*2C*20*40message*0A*20*20*20*20*7C*20filter*20*40message*20not*20like*20%27example%27*0A*20*20*20*20*7C*20sort*20*40timestamp*20asc*0A*20*20*20*20*7C*20limit*20100%7EisLiveTrail%7Efalse%7Esource%7E%28%7E%27*2Fapplication*2Fsample1%7E%27*2Fapplication*2Fsample2%29%29"
Run Code Online (Sandbox Code Playgroud)

最后我们对其进行 URL 编码并替换%$vois la:

const withQueryDetail = "?queryDetail=%7E%28end%7E0%7Estart%7E-3600%7EtimeType%7E%27RELATIVE%7Eunit%7E%27seconds%7EeditorString%7E%27fields*20*40timestamp*2C*20*40message*0A*20*20*20*20*7C*20filter*20*40message*20not*20like*20%27example%27*0A*20*20*20*20*7C*20sort*20*40timestamp*20asc*0A*20*20*20*20*7C*20limit*20100%7EisLiveTrail%7Efalse%7Esource%7E%28%7E%27*2Fapplication*2Fsample1%7E%27*2Fapplication*2Fsample2%29%29"
Run Code Online (Sandbox Code Playgroud)

把它们放在一起:

const result = "$3FqueryDetail$3D$257E$2528end$257E0$257Estart$257E-3600$257EtimeType$257E$2527RELATIVE$257Eunit$257E$2527seconds$257EeditorString$257E$2527fields*20*40timestamp*2C*20*40message*0A*20*20*20*20*7C*20filter*20*40message*20not*20like*20$2527example$2527*0A*20*20*20*20*7C*20sort*20*40timestamp*20asc*0A*20*20*20*20*7C*20limit*20100$257EisLiveTrail$257Efalse$257Esource$257E$2528$257E$2527*2Fapplication*2Fsample1$257E$2527*2Fapplication*2Fsample2$2529$2529"
Run Code Online (Sandbox Code Playgroud)

当然也可以进行反向操作。

这就是大家。玩得开心,小心,尽量避免自己做这种奇怪的事情。:)


Pål*_*erg 6

我不得不做类似的事情来生成一个指向 lambda 日志的反向链接,并做了以下骇人听闻的事情来创建链接:

const link = `https://${process.env.AWS_REGION}.console.aws.amazon.com/cloudwatch/home?region=${process.env.AWS_REGION}#logsV2:log-groups/log-group/${process.env.AWS_LAMBDA_LOG_GROUP_NAME.replace(/\//g, '$252F')}/log-events/${process.env.AWS_LAMBDA_LOG_STREAM_NAME.replace('$', '$2524').replace('[', '$255B').replace(']', '$255D').replace(/\//g, '$252F')}`
Run Code Online (Sandbox Code Playgroud)

  • 显然有一个更简单的链接可以为您进行编码/替换:`https://console.aws.amazon.com/cloudwatch/home?region=${process.env.AWS_REGION}#logEventViewer:group=${logGroup };流=${logStream}` (2认同)

isa*_*s-b 6

我的一位同事发现编码没有什么特别之处。它是标准的 URI百分比编码,但应用了两次 (2x)。在 javascript 中,您可以使用该encodeURIComponent函数进行测试:

let inp = 'https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/'

console.log(encodeURIComponent(inp))
console.log(encodeURIComponent(encodeURIComponent(inp)))
Run Code Online (Sandbox Code Playgroud)

这段 javascript 在第二个编码阶段产生预期的输出:

https%3A%2F%2Fconsole.aws.amazon.com%2Fcloudwatch%2Fhome%3Fregion%3Dus-east-1%23logsV2%3Alog-groups%2Flog-group%2F
https%253A%252F%252Fconsole.aws.amazon.com%252Fcloudwatch%252Fhome%253Fregion%253Dus-east-1%2523logsV2%253Alog-groups%252Flog-group%252F
Run Code Online (Sandbox Code Playgroud)

警告

至少有些位使用双重编码,但不是整个链接。否则所有特殊字符在双重编码后都会占用4个字符,但有些仍然只占用2个字符。无论如何,希望这会有所帮助;)

  • 很好的解决方案,但我认为你仍然需要用“$”替换“%”?我有一个 `const awsEncode = text =>encodeURIComponent(encodeURIComponent(text)).replace(/%/g, '$');` 函数来帮助我做到这一点 (2认同)

Ric*_*urt 2

我创建了一些 Ruby 代码,似乎可以满足 CloudWatch URL 解析器的要求。我不知道为什么你必须双重转义一些东西,然后%$其他东西替换。我猜这背后有一些原因,但我找不到一个好的方法来做到这一点,所以我只是暴力地强迫它。如果您有更好的东西,或者知道他们为什么这样做,请添加评论。

注意:filter我测试的有点基本,我不确定如果你真的喜欢它,可能需要改变什么。

# Basic URL that is the same across all requests
url = 'https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/'

# CloudWatch log group
log_group = '/aws/my/log/group'

# Either specify the instance you want to search or leave it out to search all instances
instance = '/log-events/i-xxxxxxxxxxxx'
 OR
instance = '/log-events'

# The filter to apply.
filter = '[incoming_ip, user_name, user_ip , timestamp, request, status_code = 5*, bytes, url, user_agent]'

# Start time.  There might be an End time as well but my queries haven't used 
# that yet so I'm not sure how it's formatted.  It should be pretty similar
# though.
hours = 48
start = "&start=-#{hours*60*60*1000}"

# This will get you the final URL
final = url + CGI.escape(CGI.escape(log_group)) + instance + '$3FfilterPattern$3D' + CGI.escape(CGI.escape(filter)).gsub('%','$') + CGI.escape(start).gsub('%','$')

Run Code Online (Sandbox Code Playgroud)