缘由
写这篇文章的原因是因为在项目开发中需要使用日志收集框架,但是发现现有的日志收集工具并不能完全满足我们的需求。我们需要一些定制化的功能,涉及到读取Oracle日志,但是网上关于这方面的资料比较分散,不好找到全面的介绍。因此花费了很多时间,于是便打算记录下来。
适用人员
有一定fluentd基础的人,会一点ruby的就更好了
Fluentd
Fluentd是一款开源的日志收集工具,可以帮助您从各种不同的数据源(例如Docker容器,Apache Web服务器等)收集日志数据。使用Fluentd,您可以将数据发送到多种目标,包括Elasticsearch,Amazon S3和MongoDB等。Fluentd还支持插件来扩展其功能,因此您可以自定义它以满足您的需求。
Fluentd的官方文档可以在此找到:https://docs.fluentd.org/
Fluent Bit
Fluent Bit是Fluentd的轻量级版本,专为嵌入到其他应用程序和服务中而设计。它可以收集来自多个数据源的日志,并将其转发到多个目标。Fluent Bit还支持插件来扩展其功能。
你可以在这里找到Fluent Bit的官方文档:https://docs.fluentbit.io/
项目背景
- 客户的项目有多个,想要把日志统一收集起来保存到mongo中,同时开发一个系统用于对收集起来的日志进行查看审查等操作
- 需要收集的日志有文件,有服务器相关的日志,有数据库日志。前两者都是读取文件的,这种官方文档已经说的很清楚了,这里就不做赘述
- 项目的需求,需要读取Oracle操作日志,并写入mongo中。也是本章所要讲述的内容
方案选择
难点,由于本人非专业DBA,对Oracle并不是非常熟悉,花的时间就比较多了。
主要的方案有三种:
- 读取ORACLE 日志文件,这个方案从网上查了很多,根据网上的方法也找到了日志文件,但是基本上是乱码,或者里面的内容极少。可能是打开方式不对,总之没有成功。本来是首选,但是卡在找不到可以解析的文件,所以没有使用。
- 读取视图v$sql,该视图会记录所有对数据库的增删改查的操作,可以直接SQL查询得到数据,本文使用这种方法,通过fluentd读取v$sql视图,并存入mongo中
- 监听数据库操作并记录到文件中,fluentbit读取该文件并发送到fluentd进行保存,由于对fluentd接触的不多,所以如何通过这种插件不知道要如何实现,使用java倒是可以,但是,这样需要多维护一个项目,麻烦,且稳定性肯定没有直接用fluentd好
正文
好了,也该进入正文了,先做一下准备
- fluentd是使用ruby编写的,ruby要连接Oracle,需要安装oracle 客户端,这里使用官方的轻量级的oracle客户端, oracle instant client,官网下载之后,设置环境变量即可
- 这里会用到fluentd的插件fluent-plugin-sql,以及基于ruby的oracle orm框架 activerecord-oracle_enhanced-adapter
- fluent-plugin-sql 这个插件,提供一个input插件和output插件,input插件用于读取数据库的表数据,output插件用于将收集到的日志保存到数据库中
- activerecord-oracle_enhanced-adapter是oracle的适配器,fluent-plugin-sql可以适配,但是由于需要查oracle视图 v$sql,视图名有特殊符号,所以fluent-plugin-sql不能直接用需要改造
- 因为要存入mongo, 所以还需要安装插件fluent-plugin-mongo
这里我没有在本机安装,而是使用docker,官方的fluentd包含上述的插件,需要自己构建镜像,这里就以docker环境下作为例子
- 下载oracle instant client,并设置环境变量
ENV ORACLE_HOME=/oracle_client/instantclient_12_2
ENV TNS_ADMIN=$ORACLE_HOME/network/admin
ENV NLS_DATE_FORMAT="yyyy-mm-dd hh24:mi:ss"
ENV OCI_DIR=$ORACLE_HOME:$OCI_DIR
ENV LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
ENV PATH=$ORACLE_HOME:$PATH
ADD ./instantclient_12_2 /oracle_client/instantclient_12_2
ADD ./ora_conf /etc/ld.so.conf.d
- 安装插件
RUN sudo gem install fluent-plugin-mongo
&& sudo gem install fluent-plugin-sql --no-document
&& sudo gem install activerecord-oracle_enhanced-adapter
&& sudo gem install ruby-oci8
- 编写fluentd配置文件,这里仅贴出INPUT
<source>
@type sql
adapter oracle_enhanced
host ORACLEHOST
port ORACLE_PORT
database db
username 用户名
password 密码
tag_prefix my.rdb # optional, but recommended
select_interval 1s # optional
select_limit 500 # optional
state_file /fluentd/sql_state
<table>
table v$sql
tag oracle
update_column last_load_time
time_column last_load_time # optional
</table>
# detects all tables instead of <table> sections
#all_tables
</source>
本来呢按道理这样就可以,美美的去启动了fluentd
但是好事多磨,一直提示 can’t connect to database. Reconnect at next try
一下子懵了,数据库配置应该没有错啊,怎么会连接不上,不信这个邪,于是又给本地装了ruby,试一下看看是什么问题,结果ruby也连不上,这就傻眼了,网上到处找,皇天不负有心人,终于找到了,不知道哪里的文章了,原来需要设置Oracle 的NLS_LANG参数,然后加上了这句,ruby和fluentd都可以连上了
ENV NLS_LANG=American_America.UTF8
开开心心继续,还是嘎了,报错了,这回是ruby转实体异常了,感觉像是表名的问题, 于是换上其他正常的表,就可以正常读取了
<table>
table v$sql------->此处换成正常的表
tag oracle
update_column last_load_time
time_column last_load_time # optional
</table>
于是,看了一下fluent-plugin-sql的源码,这里会将 “.”转换为_,破案了,v$sql作为实体名,这个在哪个语言里都是不行的,$是特殊符号,也要转一下,于是把这段改了一下
# ActiveRecord requires model class to have a name.
class_name = table_name.gsub(/\./, "_").singularize.camelize
base_model.const_set(class_name, @model)
改成
class_name = table_name.gsub(/\$|\./, "_").singularize.camelize
这样终于成功了, 由于这里自己用的,就没有把修改后的插件上传到rubygem了,使用本地安装,并把fluent-plugin-sql源码拷贝到插件目录中
cd /fluentd/plugins/fluent-plugin-sql/
# 生成fluent-plugin-sql-2.3.0.gem
gem build fluent-plugin-sql.gemspec
#本地安装
fluent-gem install --local fluent-plugin-sql-2.3.0.gem
# 修改后的fluent-plugin-sql源码拷贝到插件目录中
cp -R fluent-plugin-sql-master /usr/local/bundle/gems/fluent-plugin-sql-2.3.0
然后就大功告成了
这里贴出完整的文件来,同时github地址也贴出来了,里面有镜像所需的所有文件
https://github.com/wxsunseas/docker-fluentd-oracle.git
#mac docker buildx build --platform linux/x86_64 -t fluentd-ora .
#其他 docker build -t fluent .
FROM fluent/fluentd:edge-debian
# Use root account to use apt
USER root
# below RUN includes plugin as examples elasticsearch is not required
# you may customize including plugins as you wish
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list
ENV ORACLE_HOME=/oracle_client/instantclient_12_2
ENV TNS_ADMIN=$ORACLE_HOME/network/admin
# ENV NLS_LANG=SIMPLIFTED_CHINESE_CHINA_ZHS16GBK
# NLS_LANG设置错误可能导致ORACLE数据库连接不上
ENV NLS_LANG=American_America.UTF8
ENV NLS_DATE_FORMAT="yyyy-mm-dd hh24:mi:ss"
ENV OCI_DIR=$ORACLE_HOME:$OCI_DIR
ENV LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
ENV PATH=$ORACLE_HOME:$PATH
ADD ./instantclient_12_2 /oracle_client/instantclient_12_2
ADD ./ora_conf /etc/ld.so.conf.d
ADD ./plugin /fluentd/plugins
RUN echo \
&& cd /oracle_client/instantclient_12_2\
&& ln -s libclntsh.so.12.1 libclntsh.so \
&& ln -s libocci.so.12.1 libocci.so
RUN buildDeps="sudo make gcc g++ libc-dev" \
&& apt-get update \
&& apt-get install -y libaio1 \
&& apt-get install -y --no-install-recommends $buildDeps
RUN gem sources -r https://rubygems.org/ -a https://gems.ruby-china.com/
RUN echo
RUN gem install activerecord -v 6.1
RUN gem install activerecord-import
# 从本地安装fluent插件, 因为fluent-plugin-sql b不支持表名带$,所以修改了一个,本地插件需要 bundle install & gem build fluent-plugin-sql.gemspec
# RUN cd /fluentd/plugins/fluent-plugin-sql/ && gem build fluent-plugin-sql.gemspec
RUN cd /fluentd/plugins/fluent-plugin-sql-master/ && fluent-gem install --local fluent-plugin-sql-2.3.0.gem
ADD ./plugin/fluent-plugin-sql-master /usr/local/bundle/gems/fluent-plugin-sql-2.3.0
RUN sudo gem install fluent-plugin-mongo
# && sudo gem install fluent-plugin-sql --no-document \
# && sudo gem install rails \
RUN sudo gem install activerecord-oracle_enhanced-adapter
RUN sudo gem install ruby-oci8
RUN sudo gem sources --clear-all \
&& SUDO_FORCE_REMOVE=yes \
apt-get purge -y --auto-remove \
-o APT::AutoRemove::RecommendsImportant=false \
$buildDeps \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem
COPY ./conf/fluent.conf /fluentd/etc/
# COPY entrypoint.sh /bin/
USER fluent
ENTRYPOINT ["/bin/sh", "-c", "fluentd -c /fluentd/etc/fluent.conf"]