将日志记录到数据库而不是日志文件中

65
我有兴趣将所有Rails应用程序日志发送到一个数据库(MySQL或MongoDB),这些日志可以替代或者同时记录在日志文件中。有几个原因,其中大部分与日志文件分析有关。我们已经使用了Google Analytics,但是我们想要做的一些事情在Analytics中不太可行。
此外,我想通过查看日志来进行“实时”问题调查。翻阅日志文件是一种繁琐的方式,我希望能够进行更好的搜索和过滤,以及比日志文件更易于操作的搜索和过滤。
最后,我经常想要检查更接近站点访问者行为的东西:例如对网站路径的追踪,以便我可以在错误发生之前看到用户正在查看的最后一个页面。鉴于我们有多个应用服务器,单独的日志文件会使这变得非常麻烦。如果所有数据都在数据库中,那么我就可以轻松地查看给定访问者的正确页面序列。我知道Syslog是解决这个特定问题的一种方法(单个日志文件/存储库),但我想将其与我所关联的更好的搜索功能相结合。
我想知道其他人推荐什么来解决这个问题。您是直接记录到数据库还是将日志文件转储到数据库(但是如果要使其与日志文件本身一样实时/最新,则应采用什么方法)?
我目前正在确定在什么级别上进行此记录,因为我查看的另一件事是编写一个小的Rack过滤器,它将记录所有请求。这将忽略常规Rails日志记录输出的所有额外输出(SQL和缓存命中和未命中的所有输出等),但它将实现我的目标的一大部分,并且似乎具有不扰乱系统中其他任何内容的优点。
总之,我不是在寻找一个正确的答案,而是希望讨论和了解其他人在同一方面做了什么。

只是好奇,Rails应用程序日志有什么特别之处?它是否类似于Web访问日志记录请求?还是你指的是实际的应用程序逻辑? - Dima
请看下面的评论:我更关心应用程序级别的日志记录,但这并不是完全必需的,同时我也不想记录由Web服务器提供的静态文件(图像、CSS等)。我们使用Hoptoad进行异常日志记录/通知,这是一个很好的解决方案。我的问题实际上是请求/调查有没有其他人实现了类似的解决方案。 - chrisrbailey
1
最近,我在尝试使用Papertrail。他们提供了非常简单的设置方式,可以将你的日志文件(Rails、Nginx或任何其他类型的日志文件)实时地传输到他们的系统中,并且支持全文搜索。这看起来非常有前途。虽然他们仍处于私人测试阶段,但是很有前途。Loggly也有潜力,但我发现它运行速度较慢,并且无法正确地处理多行日志消息(可能只是我的操作问题,但我在他们的支持论坛上也没有得到答复)。Graylog2和logstash也值得一试。 - chrisrbailey
5个回答

41

我们公司一直将一些结构化的流量信息直接记录在MySQL日志数据库中。该数据库会被复制到另一个数据库。所有分析都是从最终数据库副本运行的。我们的网站承载着相当多的流量。目前为止,似乎没有任何主要问题。然而,我们的IT部门对当前设置的可扩展性有一些担忧,并建议我们将日志信息转移到“适当”的日志文件上。然后将日志文件重新插入到同一下游数据库表中。这就引出了我要提出的问题。

以下是我认为关于日志文件与日志数据库(关联型)的优缺点:

  • 日志文件快速、可靠且可扩展(至少我听说Yahoo!在其点击跟踪分析中大量使用日志文件)。
  • 日志文件易于系统管理员维护。
  • 日志文件非常灵活,因为您几乎可以将任何内容写入其中。
  • 日志文件需要进行重度解析和潜在的映射式设置以进行数据提取。
  • 日志数据库结构更接近于应用程序,使某些功能的周转时间更短。这可能是好事也可能是坏事。长远来看可能是坏事,因为您很可能最终会拥有高度耦合的应用程序和分析代码库。
  • 日志数据库可以减少日志噪音和冗余,因为日志文件是仅插入的,而日志数据库则使您能够进行更新和关联插入(如果你敢使用规范化)。
  • 如果选择使用数据库划分和/或多个日志数据库(通过下游副本重新连接数据),则日志数据库也可以快速且可扩展。

我认为在我的情况下需要对日志数据库进行一些压力测试。这样至少我就知道有多少余地了。

最近,我一直在研究一些键值/文档型数据库,比如Redis、Tokyo Cabinet和MongoDB。这些快速插入的数据库可能是最理想的选择,因为它们提供了各种程度的持久性、高(写)吞吐量和查询能力。它们可以使数据提取过程比解析和映射减少大量日志文件更加简单。

从长远来看,我认为拥有一个强大的分析数据仓库非常重要。将应用程序数据与分析数据分离开来,互不干扰,这可能是一个很大的优势。


最后,我想指出,在StackOverflow上有许多类似/密切相关的问题,如果您想扩大讨论的话。


编辑:

rsyslog看起来非常有趣。它使您能够直接写入MySQL。如果您使用Ruby,请查看logging gem。它提供多目标日志记录功能。非常好用。


谢谢以上内容。我一直在研究MongoDB,现在我正在倾向于使用它。我需要解决的最大问题是如何将数据导入其中。例如,我是否定期解析日志文件,从而使我的应用程序不受影响(这很好),但会使事情变得相当困难(解析Rails日志输出可能很痛苦(也许?)。或者,我是否编写自己的Rails记录器,将其发送到当前日志(因此如果MongoDB出现问题,我仍然可以获得常规文件记录),以及写入MongoDB或其他解决方案等。 - chrisrbailey

9
如果您想更改默认日志记录行为,只需创建一个自定义的日志记录器对象,该对象响应所有Rails日志记录器方法:
  • add
  • debug、warn、error、info、fatal、unknown
http://github.com/rails/rails/blob/9d7aae710384fb5f04129c35b86c5ea5fb9d83a9/activesupport/lib/active_support/buffered_logger.rb 由于它是您的日志记录器,您可以决定实现个人逻辑。您可以将日志内容写入数据库、标准输出或任何您想要的位置。
然后,将每个要自定义的基类的默认日志记录器替换为自定义日志记录器。
ActiveRecord::Base.logger = YouLogger.new

您可以轻松地创建一个名为logger.rb的初始化文件,并在其中编写所有自定义配置。这样,在Rails启动时,记录器将立即被替换掉。

1
谢谢。我应该提到我知道那个选项,但对其他人来说这是好的笔记。主要是我想知道其他人是如何做到这一点的,他们做了什么选择等等。例如,如果你用这种方式做,速度/性能方面有哪些问题 - 你是如何保持数据库连接等等(如果你甚至在使用),或者其他什么。 - chrisrbailey
这正是我正在寻找的,除了ActiveRecord::Base.logger(我使用Mongoid而不是Active Record作为数据库),还有哪些其他日志记录器可以替换? - Julien
如果有人需要帮助的话,在Rails 4中,我所要做的就是在初始化程序中替换Rails.logger - Julien

1

由于至今没有被接受的答案,我将提供我的贡献。

我开发了一个插件来将日志保存在mongodb中而不是文件中。

整个源代码,从rsyslog +插件在这里 https://github.com/vpereira/rsyslogd-mongo

要编译它,您只需运行./configure --help并查看可用选项即可。


1

Chris,

我认为Dima的评论在这里很重要。你是否满意于(1)在实时中将访问日志记录到数据库中,或者(2)更关心Rails/应用程序特定的日志记录?

对于(1),至少使用Apache,您可以使用管道日志记录到数据库中。

http://httpd.apache.org/docs/1.3/logs.html#piped

我编写了一个在后台运行等待输入的程序,它会解析并记录到Postgres DB中。我的httpd.conf文件使用CustomLog指令将日志传输到该程序。

这相对简单设置,并且具有将日志分析到数据库中的明显优势。对于我来说非常有效,特别是用于跟踪用户在错误之前所做的操作。但是,您必须保护日志记录程序免受SQL注入、缓冲区溢出和其他安全问题的影响。

对于(2),我不是Rails开发人员,因此只能谈论一般方法。如果您想记录环境变量、应用程序数据或非常选择性的信息位,可以考虑编写Web服务器模块。根据您的确切需求,您还可以通过条件日志记录指令和日志记录程序中的过滤器的组合来实现。

这真的取决于您是否需要Rails特定的解决方案还是更通用的Web服务器范围的解决方案。


我们不用Apache(使用Nginx),但这是一个好点。我更喜欢类似于Rails日志的东西,因为我想要应用级别的日志记录,而不是Web服务器日志。我不关心所有请求的图像和CSS等内容,而且我宁愿有特定于应用程序的日志记录,而不是URL。这真的意味着我需要在Rails层面上做日志记录(因为即使在Rack层面上,它仍然只是URL,尽管它将筛选出由Nginx提供服务的静态资源),但为了速度和其他方面的考虑,我可能需要在Rack层面上进行记录。 - chrisrbailey

1
最近我犯了一个错误,将日志记录到数据库中,我认为这是不应该这样做的一个非常好的理由:事务。假设您开始一个事务,在事务过程中记录了大量的内容,最终出现了错误条件。您记录了错误条件,但是噢,ROLLBACK。突然间,您刚刚记录的所有内容都消失了,您不知道发生了什么或者为什么会这样。

特别是在Rails的上下文中,像AASM这样非常有用的库会将许多东西包装在事务中,您可能会在没有想到的地方遇到事务,这也使得问题非常难以调试。

在我的情况下,我将日志记录到数据库中的原因是我需要上下文敏感的日志。基本上,我需要能够查找与特定数据库模型相关的所有日志条目。然而,正确的答案是将这些日志放在更适合日志数据的某个单独位置(在我的情况下,这个位置可以查询)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接