注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

syslog-ng之部分flags实现注释  

2012-07-29 17:21:10|  分类: Linux系统编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、log语句
顾名思义,log是整个syslog-ng的核心,因为整个过程都是为了让我们能够将感兴趣的事件源信息记录到指定的位置,而这基本的操作在syslog-ng中就是通过log语句来声明的。对于简单的语句来说,都没有什么可以说明的,但是对于复杂一些的系统,可能使用到一些特殊的标志来完成系统信息的记录和提取,此时就需要知道一些比较生僻的或者不太常用的语句的意义。
这里主要是通过对syslog-ng一些标志位的意义解释及实现来说明一下syslog-ng的一些实现细节。
二、flags
在很多的语句中,flags是一个扩展的功能,它能够对一些语句进行功能的边缘性修正和完善,例如match语句中对于正则表达式的是否区分大小写的修饰说明,以及log中对于是否要继续路由这个消息进行特殊的说明。这里依然是我们最为感兴趣的log语句的说明,它是整个日志系统的基础,而其中的flags的意义在常见的中文手册中并没有找到说明,所以此处进行注释。
常见的flags包含了 fallback、final、catchall等指令,它们在一般的日志中是不会出现的,只是稍微复杂的系统可能会使用到这些功能。
三、log语句的解析实现
对于整个一个log语句的解释,位于源代码中的center.c文件的log_center_init_pipe_line函数,其中对于各个log事件进行了静态重定位信息。所谓的静态重定位就是对于source filter destination 各种信息根据log的声明连接在一起,而连接的过程就是一些管道,从程序的角度来看,也可以认为是一些重定位的过程。
该函数是整个log解析的核心,为了具体说明一下,这里比较老套的把源代码贴出来逐个分析一下,可能会占用比较多的篇幅

/* NOTE: returns a borrowed reference! */
LogPipe *
log_center_init_pipe_line(LogCenter *self, LogConnection *conn, GlobalConfig *cfg, gboolean toplevel, gboolean flow_controlled_parent)
{
  LogPipeItem *ep;
  LogPipe *first_pipe, *pipe, *last_pipe, *sub_pipe;
……
 
  first_pipe = last_pipe = NULL;
 
  pipe = NULL;
  for (ep = conn->endpoints; ep; ep = ep->ep_next)这里是便利一个log中的所有项,这些项包含了source、filter、rewrite、pipe等各种说明信息,它们均包含在一个log语句中。
    {
      g_assert(pipe == NULL);

      /* this switch results in a borrowed reference to be stored in @pipe */
      switch (ep->type)
        {
        case EP_SOURCE:
          if (toplevel && (conn->flags & LC_CATCHALL) == 0)使能了catchall标志的log不能包含source说明
            {
              ep->ref = g_hash_table_lookup(cfg->sources, ep->name->str);查找事件源,以字符串为标志
              if (!ep->ref)
                {
                  msg_error("Error in configuration, unresolved source reference",
                            evt_tag_str("source", ep->name->str),
                            NULL);
                  goto error;
                }
              log_source_group_ref((LogSourceGroup *) ep->ref);
              pipe = (LogPipe *) ep->ref;
              g_ptr_array_add(self->initialized_pipes, log_pipe_ref(pipe));

              if (!pipe->pipe_next)
                {
                  mpx = log_multiplexer_new(PIF_MPX_FLOW_CTRL_BARRIER);
                  g_ptr_array_add(self->initialized_pipes, mpx);
                  log_pipe_append(pipe, &mpx->super);
                }
              pipe = NULL;清空pipe,也就是source始终不会作为这个log语句的法人代表
            }
          else if (!toplevel)
            {
              msg_error("Error in configuration, no source reference is permitted in non-toplevel log statements",
                        NULL);
              goto error;
            }
          else
            {
              msg_error("Error in configuration, catch-all log statements may not specify sources",
                        NULL);
              goto error;
            }
          break;
        case EP_FILTER:log中filter功能处理
          {
            LogProcessRule *rule;

            rule = ep->ref = g_hash_table_lookup(cfg->filters, ep->name->str);
            if (!ep->ref)
              {
                msg_error("Error in configuration, unresolved filter reference",
                          evt_tag_str("filter", ep->name->str),
                          NULL);
                goto error;
              }
            log_process_rule_ref(rule);
            pipe = log_process_pipe_new(rule); pipe被赋值,有可能作为整个log语句的法人代表
            g_ptr_array_add(self->initialized_pipes, pipe);
            if (rule->modify)
              path_changes_the_message = TRUE;
            break;
          }
        case EP_PARSER:
        ……
          break;
        case EP_DESTINATION:
          ep->ref = g_hash_table_lookup(cfg->destinations, ep->name->str);
          if (!ep->ref)
            {
              msg_error("Error in configuration, unresolved destination reference",
                        evt_tag_str("destination", ep->name->str),
                        NULL);
              return FALSE;
            }
          log_dest_group_ref((LogDestGroup *) ep->ref);
          g_ptr_array_add(self->initialized_pipes, log_pipe_ref((LogPipe *) ep->ref));
         
          pipe = (LogPipe *) log_multiplexer_new(0);创建一个新的多工转发结构,多工结构的下一跳指向destination描述的目的地
          log_multiplexer_add_next_hop((LogMultiplexer *) pipe, ep->ref);
          g_ptr_array_add(self->initialized_pipes, pipe);
          break;
        case EP_PIPE:
        ……
          break;
        case EP_REWRITE:
   ……
          break;
        default:
          g_assert_not_reached();
          break;
        }
       
      /* pipe is only a borrowed reference */
      if (pipe)
        {
          if (!first_pipe)
            first_pipe = pipe;遇到的第一个非source命令作为整个log语句的代表,整个语句的标志位设置在该pipe中

          if (last_pipe)
            {
              log_pipe_append(last_pipe, pipe);
              last_pipe = pipe;
              pipe = NULL;
            }
          else
            {
              last_pipe = pipe;
              pipe = NULL;
            }

          while (last_pipe->pipe_next)
            last_pipe = last_pipe->pipe_next;
        }
    }
 
  if (!first_pipe)
    {
      /* FIXME: more accurate description of the error */
      msg_error("Pipeline has no processing elements, only sources", NULL);
      goto error;
    }
 
  if (conn->flags & LC_FALLBACK)
    first_pipe->flags |= PIF_FALLBACK;
  if (conn->flags & LC_FINAL)
    first_pipe->flags |= PIF_FINAL;
  if ((conn->flags & LC_FLOW_CONTROL) || flow_controlled_child || flow_controlled_parent)
    first_pipe->flags |= PIF_FLOW_CONTROL;
  if (path_changes_the_message)
    first_pipe->flags |= PIF_CLONE;
   
  if ((conn->flags & LC_CATCHALL) == 0)
    {
      for (ep = conn->endpoints; ep; ep = ep->ep_next)
        {
          if (ep->type == EP_SOURCE)
            {
              pipe = (LogPipe *) ep->ref;
              mpx = (LogMultiplexer *) pipe->pipe_next;
              log_multiplexer_add_next_hop(mpx, first_pipe);如果整个log没有设置catchall标志,那么这里遍历log中所有的source,将这个log语句挂接到这个source的下一跳处理链表中,注意,这里是依次挂接的,新声明的log在跳转表的后面。这也意味着一个source中所有的下一条都在自己的next_hops结构中,而这个结构中所有下一条是一个线性一维结构,这一点对于之后final的解释非常重要
              pipe = NULL;
            }
        }
    }
  else
    {
      gpointer args[] = { self, first_pipe };
      g_hash_table_foreach(cfg->sources, log_center_connect_source, args);如果设置了catchall标志,将这个log语句挂接到系统中所有的source节点的next_hops结构中,这是一个霸道的全面撒网做法
    }
  return first_pipe;
 error:
 
  /* we don't need to free anything, everything we allocated is recorded in
   * @self, thus will be freed whenever log_center_free is called */
 
  return NULL;
}
四、flags语句对日志的运行时影响

static void
log_multiplexer_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options)
{
  LogMultiplexer *self = (LogMultiplexer *) s;
  gint i;
  LogPathOptions local_options = LOG_PATH_OPTIONS_INIT;
  gboolean matched;
  gboolean delivered = FALSE;
  gboolean last_delivery;
  gint fallback;
 
  local_options.matched = &matched;
 
  for (fallback = 0; (fallback == 0) || (fallback == 1 && self->fallback_exists && !delivered); fallback++)这个循环其实最多只会被执行两次,如果第一次没有任何log处理这个消息,那么第二次循环会尝试派发给fallback向来处理和记录这个消息。第二次循环可以执行的条件就是存在fallback向,并且这个消息在前一轮中没有被发送出去
    {
      for (i = 0; i < self->next_hops->len; i++)这里其实就是便利一个source的所有的next_hops,在上一个函数中我们已经看到,它在静态读取配置之后已经被初始化为所有log语句中包含有该source的记录动作,这里是一个线性便利一个source所有的log的过程
        {
          LogPipe *next_hop = g_ptr_array_index(self->next_hops, i);
          LogMessage *next_msg = NULL;

          if (G_UNLIKELY(fallback == 0 && (next_hop->flags & PIF_FALLBACK) != 0))
            {第一次循环是不会考虑fallback属性的记录项
              continue;
            }
          else if (G_UNLIKELY(fallback && (next_hop->flags & PIF_FALLBACK) == 0))
            {第二次循环只会考虑具有fallback属性的记录项
              continue;
            }
         
          if (self->super.flags & PIF_MPX_FLOW_CTRL_BARRIER)
            local_options.flow_control = (next_hop->flags & PIF_FLOW_CONTROL) ? TRUE : FALSE;
          else
            local_options.flow_control = path_options->flow_control;
           
          matched = TRUE;
          log_msg_add_ack(msg, &local_options);
         
     ……
            }
          else
            next_msg = log_msg_ref(msg);

          log_pipe_queue(next_hop, next_msg, &local_options);
         
          if (matched)
            {
              delivered = TRUE;
              if (G_UNLIKELY(next_hop->flags & PIF_FINAL))这里就是对于final标志的处理,如果遇到该标志的记录项,整个循环退出。大家要记得之前说过的编译时会将source的所有log项记录到该source的next_hops中,所以这意味着整个文件中的final之后的log向不会再被处理
                break;
            }
        }
    }
  log_pipe_forward_msg(s, msg, path_options);
}
五、catchall的生效时机
在前面我们看到catchall添加到所有的事件源中同样是按照顺序来添加的,而在运行时匹配的时候依然是顺序检测的。如果说具有catchall的log放置在了具有final属性的log语句之后,那么这个catchall病不能够记录系统中的所有事件。
[tsecer@Harry etc]$ cat /usr/local/etc/syslog-ng.conf
#############################################################################
# Default syslog-ng.conf file which collects all local logs into a
# single file called /var/log/messages.
#

@version: 3.2
@include "scl.conf"

source s_local {
    system();
    internal();
};

source s_network {
    udp();
};

destination d_local {
    file("/var/log/messages");
};
destination d_back {
    file("/var/log/tsecer");
};
destination  catchall {
    file ("/var/log/catchall");
};
#log {
#    destination(catchall);
#    flags(catchall);
#};
log {
    source(s_local);

    # uncomment this line to open port 514 to receive messages
    #source(s_network);
    destination(d_local);
    flags(final);
};
log {
    source(s_local);
    destination(d_back);
};
log {
    destination(catchall);
    flags(catchall); 由于该catchall声明放置到了final的后面,所以它不能记录系统中的所有日志信息,事实上它记录不到系统中的任何信息。
}
;
  评论这张
 
阅读(1238)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017