3

我正在梳理一个 webapp 的日志文件,以获得突出的语句。

大多数线条相似且无趣。我会通过 Unix 传递它们uniq,但是不会过滤任何内容,因为所有行都略有不同:它们都有不同的时间戳,类似的语句可能会打印不同的用户 ID,等等。

有什么方法和/或工具来获得与其他明显不同的线条?(但是,再次,不是精确的重复)

我正在考虑使用 Python 的difflib,但这似乎是为了区分两个文件,而不是同一文件中的所有行对。

[编辑]

我假设该解决方案将为每一行给出一个唯一性分数。因此,我的意思是“显着不同”,我选择了一个阈值,该阈值必须超过唯一性得分才能使任何行包含在输出中。

在此基础上,如果还有其他可行的定义方式,欢迎讨论。此外,该方法不必具有 100% 的准确率和召回率。

[/编辑]

例子:

我更喜欢尽可能通用的答案。我知道我可以在开始时去掉时间戳。剥离结尾更具挑战性,因为它的语言可能与文件中的任何其他内容完全不同。这些细节是我之前回避具体例子的原因,但因为有人问......

类似1:

2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234
2009-04-20 00:04:02 INFO  com.foo.Bar - URL:/graph?id=asdfghjk

类似2:

2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses
2009-04-20 00:06:00 INFO  com.baz.abc.Accessor - Cache /path/to/some/different/dir hits: 4352685 / 271315, 0.004423% misses

不同1:

2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234
2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses

在不同的 1 情况下,我希望返回两条线,但不希望返回类似它们的其他线。换句话说,这两条线是不同的类型(然后我可以稍后只要求统计上罕见的线类型)。一方面,这两者之间的编辑距离要大得多。

4

6 回答 6

3

定义“显着不同”。然后看看“编辑距离”措施

于 2009-04-20T19:35:08.927 回答
2

您可以尝试一些计算单词的代码,然后按最不常用单词对行进行排序。

如果这不起作用,您可以添加一些智能来过滤掉时间戳和数字。

您的问题类似于之前关于生成新闻故事摘要的问题。

于 2009-04-20T19:35:15.900 回答
2

我不知道适合你的工具,但如果要自己动手,我会这样处理:

大概日志行具有明确定义的结构,不是吗?所以

  • 解析该结构上的行
  • 编写一些非常基本的相关过滤器(只从解析的结构中返回一个简单数字的函数)
  • 通过一组过滤器运行解析的行,并根据总分进行切割
  • 可能通过更多过滤器的结果将剩余的行分类到不同的箱中
  • 生成报告、将 bin 转储到文件或其他输出

如果您熟悉 unix 工具procmail,我建议为您的数据定制类似的处理方法。


正如评论中的 zacherates 所指出的,您的过滤器通常会忽略时间戳(可能还有 IP 地址),而只关注内容:例如,非常长的 http 请求可能代表攻击……或任何适用于您的域的内容。

您的分箱过滤器可能就像在几个选定字段上的哈希一样简单,或者您可能会尝试按照查理马丁的建议做一些事情并使用编辑距离度量。

于 2009-04-20T19:37:47.420 回答
1

也许您可以对“相同的单词”/“所有单词”进行基本计算?

例如(包括允许您忽略时间戳和“信息”一词的偏移量,如果它们始终相同):

def score(s1, s2, offset=26):
    words1 = re.findall('\w+', s1[offset:])
    words2 = re.findall('\w+', s2[offset:])
    return float(len(set(words1) & set(words2)))/max(len(set(words1)), len(set(words2)))

鉴于:

>>> s1
'2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234'
>>> s2
'2009-04-20 00:04:02 INFO  com.foo.Bar - URL:/graph?id=asdfghjk'
>>> s3
'2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses'
>>> s4
'2009-04-20 00:06:00 INFO  com.baz.abc.Accessor - Cache /path/to/some/different/dir hits: 4352685 / 271315, 0.004423% misses'

这产生:

>>> score(s1,s2)
0.8571428571428571
>>> score(s3,s4)
0.75
>>> score(s1,s3)
0.066666666666666666

You've still got to decide which lines to compare. Also the use of set() may distort the scores slightly – the price of a simple algorithm :-)

于 2009-04-21T02:21:56.390 回答
0

我想知道您是否可以只专注于为您定义独特性的部分。在这种情况下,似乎定义唯一性的部分只是中间部分:

2009-04-20 00:03:57 信息 com.foo.Bar - URL:/graph?id=1234
                    ^---------------------^

2009-04-20 00:05:59 信息 com.baz.abc.Accessor - 缓存 /path/to/some/dir 命中:3466 / 16534,0.102818% 未命中
                    ^--------------------------------^

然后,我将准确比较这部分,也许使用正则表达式(只是带括号的组;如何访问这样的子匹配取决于语言):

/^.{20}(\w+\s+[\w\.-]+\s+-\s+\w+)/
于 2009-04-21T00:26:14.450 回答
0

我认为您想将其分解为字段,按“严重性级别”字段和下一个字段(看起来像“类”)排序。我会使用 Haskell:

模块主要在哪里
导入 Data.List (nubBy, sortBy)

sortAndNub s = nubBy fields2and3
     $ sortBy fields2and3comp
     $ 地图词 $ 线条 s

fields2and3 ab = fieldEq 2 ab
                  && fieldEq 3 ab
fieldEq fab = a!!f == (b!!f)
fields2and3comp ab = 大小写比较 (a!!2) (b!!2) of
   LT->LT
   GT -> GT
   EQ -> 比较 (a!!3) (b!!3)
main = 交互 $ unlines.(map unwords).sortAndNub
于 2009-04-21T01:16:32.490 回答