블로그 이미지
redkite

카테고리

분류 전체보기 (291)
00.SI프로젝트 산출물 (0)
00.센터 운영 문서 (0)
01.DBMS ============.. (0)
01.오라클 (117)
01.MS-SQL (15)
01.MySQL (30)
01.PostgreSql (0)
01.DB튜닝 (28)
====================.. (0)
02.SERVER ==========.. (0)
02.서버-공통 (11)
02.서버-Linux (58)
02.서버-Unix (12)
02.서버-Windows (2)
====================.. (0)
03.APPLICATION =====.. (11)
====================.. (0)
04.ETC =============.. (0)
04.보안 (5)
====================.. (0)
05.개인자료 (1)
06.캠핑관련 (0)
07.OA관련 (1)
Total
Today
Yesterday

달력

« » 2013.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

공지사항

최근에 올라온 글

  1. http://pastebin.com/A5pRDv2P

    ###INPUT###
    input {
      tcp {
        port => 514
        type => "syslog-relay"
      }
      udp {
        port => 514
        type => "syslog-relay"
        buffer_size  => 16384
      }
      gelf {
        port => 12201
        type => "gelf"
      }
    }
    filter {
      grep {
        type => "syslog-relay"
        match => [ "@message", ":\s\%ASA-" ]
        add_tag => "got_syslog_cisco"
        drop => false
        }
      grep {
        type => "syslog-relay"
        match => [ "@message", ":\s\%ASA-" ]
        add_tag => "got_syslog_standard"
        drop => false
        negate => true
        }
     
      # strip the syslog PRI part
      grok {
        type => "syslog-relay"
        pattern => [ "(?m)<%{POSINT:syslog_pri:int}>(?:%{SPACE})%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_pri"
       add_field => [ "syslog_raw_message", "%{@message}" ]
     }
     syslog_pri {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
       remove => [ "message_remainder" ]
     }
     
     # strip the syslog timestamp and force event timestamp to be the same.
     # the original string is saved in field %{syslog_timestamp}.
     # the original logstash input timestamp is saved in field %{received_at}.
     grok {
       # put cisco log timestamp in cisco_syslog_timestamp as ES can't store 2 format of dates in the same field
       # also parse the hostname if present....
       type => "syslog-relay"
       tags => [ "got_syslog_cisco" ]
       pattern => [ "(?m)%{SYSLOGTIMESTAMPWITHYEAR:cisco_syslog_timestamp}(\s+%{SYSLOGHOST:syslog_hostname}\s+\:|\:)?\s+%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_timestamp"
       add_field => [ "received_at", "%{@timestamp}" ]
     }
     grok {
       # put log timestamp in syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{TIMESTAMP_RFC3339:syslog_timestamp}%{SPACE}%{GREEDYDATA:message_remainder}", "(?m)%{SYSLOGTIMESTAMPWITHOUTYEAR:syslog_timestamp}%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_timestamp"
       add_field => [ "received_at", "%{@timestamp}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       remove => [ "message_remainder" ]
     }
     date {
       # parse the cisco_syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" , "got_syslog_cisco" ]
       cisco_syslog_timestamp => [ "MMM dd yyyy HH:mm:ss", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601" ]
     }
     date {
       # parse the syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp", "got_syslog_standard" ]
       syslog_timestamp => [ "MMM dd yyyy HH:mm:ss", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601" ]
     }
     
     # strip the host field from the syslog line.
     # the extracted host field becomes the logstash %{@source_host} metadata
     # and is also available in the filed %{syslog_hostname}.
     # the original logstash source_host is saved in field %{logstash_source}.
     
     grok {
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{SYSLOGHOST:syslog_hostname}%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_host"
       add_field => [ "logstash_source", "%{@source_host}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_host" ]
       replace => [ "@source_host", "%{syslog_hostname}", "@message", "%{message_remainder}" ]
       #replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_host" ]
       remove => [ "message_remainder" ]
     }
     
     
     # strip the app name and set it in syslog_file_name field to compute the local log file name
     grok {
       # do the stip multiline for standard syslog
       # program can still be like "program_main/program_param"
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{SYSLOGPROG:syslog_program}\:%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => [ "got_syslog_program", "%{program}" ]
       add_field => [ "syslog_file_name", "%{program}" ]
     }
     grok {
       # split the main and param part of the program
       type => "syslog-relay"
       tags => [ "got_syslog_program" ]
       match => ["program", "%{MULTIPROG}" ]
       add_tag => [ "got_syslog_program_param", "%{program_main}", "%{program_param}"  ]
     }
     
     grok {
       # do the strip single line for cisco syslog
       type => "syslog-relay"
       tags => [ "got_syslog_cisco" ]
       pattern => [ "\%%{SYSLOGPROG:syslog_program}\:%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => [ "got_syslog_program", "%{program}" ]
       add_field => [ "syslog_file_name", "%{program}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_program" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       remove => [ "message_remainder" ]
     }
     
     
     #############################################################
     #
     # Jboss logs = tag JBOSSserver
     #
     #############################################################
     
     # try to get multilines back
     multiline {
       # match 2012-07-30 10:29:55,985
       type => "syslog-relay"
       tags => "JBOSSserver"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     # remove logs which are malformed stacktraces
     grep {
       # tag the malformed stacktrace
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       match => [ "@message", "java\.lang\.Throwable" ]
       add_tag => "got_syslog_stacktrace"
       drop => false
       negate => false
       }
     
     
     # Parse jboss messages
     grok {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       pattern => [ "(?m)%{JBOSSSERVERLOG}" ]
     }
     mutate {
       # remove the timestamp at the begining of the message
       # doing this completly remove timestamp of errors in the file output module
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       replace => [ "@message", "%{jboss_loglevel} [%{jboss_class}] %{jboss_caller}: %{jboss_message}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       remove => [ "jboss_message" ]
     }
     
     
     # set the date to the Jboss error date
     date {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     
     #############################################################
     #
     # Tomcat
     #
     #############################################################
     
     # define multiline messages starting at the date
     # Feb 28, 2012 2:07:33 PM org.apache.jk.common.ChannelSocket processConnection
     # WARNING: processCallbacks status 2
     # 2012-02-28 14:10:27,723 DEBUG [shq.servlet.GetResourceFlex] - <Ressource demandee : /sde/>
     
     multiline {
       type => "syslog-relay"
       tags => "Tomcat"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     #############################################################
     #
     # OUD
     #
     #############################################################
     
     # OUD logs are XML inside <record> </record>
     multiline {
       type => "syslog-relay"
       tags => "OUDSERVER"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     #############################################################
     #
     # SHQ Synapse
     #
     #############################################################
     
     # OUD logs are XML inside <record> </record>
     multiline {
       type => "syslog-relay"
       tags => "synapse"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     multiline {
       type => "syslog-relay"
       tags => "oud"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     
     # synapse/main tagged logs
     # 2012-06-21 13:04:25,024 [10.100.64.74-qxpsbp01] [HttpServerWorker-9]  INFO
     multiline {
       type => "syslog-relay"
       tags => "synapse/main"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     multiline {
       type => "syslog-relay"
       tags => "synapse/service"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     # synapse service.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/main" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse service.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/service" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse wrapper.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/wrapper" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse trace.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/trace" ]
       pattern => [ "(?m)%{SYNAPSETRACELOG}" ]
     }
     
     # set the date to the SYNAPSE error date
     date {
       type => "syslog-relay"
       tags => [ "synapse/main" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     date {
       type => "syslog-relay"
       tags => [ "synapse/service" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     date {
       type => "syslog-relay"
       tags => [ "synapse/wrapper" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     
     
     
     
     #############################################################
     #
     # Other messages
     #
     #############################################################
     
     # rebuild multiline messages
     multiline {
       type => "gelf"
       pattern => "^\s"
       what => "previous"
     }
    }
    output {
    #  stdout {
    #  }
     
    #  gelf {
    #    chunksize => 1420
    #    facility => "logstash-gelf"              #########Default Setting ##########
    #    host => "qxplog02.corp.shq.local"
    #    level => "INFO"                             #########Default Setting ##########
    #    port => 12201
    #    sender => "%{@source_host}"
    #  }
     
     elasticsearch {
       host => "localhost"
       embedded => false
     }
     
     file {
       flush_interval => 10
       tags => ["got_syslog_standard"]
       path => "/opt/data/syslog/%{+YYYY}/%{+MM}/%{+dd}/%{@source_host}/%{syslog_file_name}.log"
       message_format => "%{@timestamp} %{@source_host} %{@message}"
     }
     
     file {
       flush_interval => 10
       tags => ["got_syslog_cisco"]
       path => "/opt/data/syslog/%{+YYYY}/%{+MM}/%{+dd}/%{@source_host}/%{program}.log"
       message_format => "%{@timestamp} %{@source_host} %{@message}"
     }
    }
     


Posted by redkite
, |

2012-05-18 10:26:01,434 INFO  [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms

I'm finding that the Severity in graylog2 is always 'Alert'. I'm using the following config file with the multiline, grok and mutate filters:

input {
  # Tail the JBoss server.log file
  file {
    type => "log4j"
    path => "/JBoss/server/all/log/server.log"
  }
}

filter {
  multiline {
    type => "log4j"
    pattern => "^\\s"
    what => "previous"
  }

  grok {
    type => "log4j"
    pattern => "%{DATESTAMP:timestamp} %{WORD:severity} %{GREEDYDATA:message}"
  }

  mutate {
    type => "log4j"
    replace => [ "@message", "%{message}" ]
  }
}

output {
  # Emit events to stdout for easy debugging of what is going through logstash
  stdout {
    debug => true
  }

  # Send Jboss log to graylog2
  gelf {
    facility => "jboss"
    host => "log01"
  }
}

Here's the logstash debug output for this log entry:

{
         "@source" => "file://stg-app01//JBoss/server/all/log/server.log",
           "@type" => "log4j",
           "@tags" => [],
         "@fields" => {
        "timestamp" => [
            [0] "2012-05-18 10:26:01,434"
        ],
         "severity" => [
            [0] "INFO"
        ],
          "message" => [
            [0] " [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms"
        ]
    },
      "@timestamp" => "2012-05-18T10:26:01.601000Z",
    "@source_host" => "stg-app01",
    "@source_path" => "//JBoss/server/all/log/server.log",
        "@message" => " [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms"
}

Finally, here's how graylog2 sees this entry:

From: stg-app01
Date: 2012-05-18 10:26:31 +0000
Severity: Alert
Facility: jboss
File: //JBoss/server/all/log/server.log:151
timestamp: 2012-05-18 10:26:01,434
severity: INFO
message: [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms
Full message:
[com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms

It has two severity entries. Am I doing something wrong?

 

 

Have a look at the "level" flag in your output configuration. In your
case you'll want to change the naming in grok to something like
"jboss_severity" and then use this in your output:

gelf {
  level =>  [%{severity}, %{jboss_severity}]
  # rest of config
}

Posted by redkite
, |

Indexing and searching Weblogic logs using Logstash and Graylog2

Recently we decided to get rid of our Splunk "Free" log indexing solution as the 500MB limit is too limited for our 20+ Weblogic environments (we couldn't even index all production apps with that) and $boss said "he won't pay over 20000€ for a 2GB enterprise license, that's just rediculous". So I went out on the interwebs to watch out for alternatives, and stumbled over Graylog2 and Logstash. This stuff seemed to have potential, so I started playing around with it.

Logstash is a log pipeline that features various input methods, filters and output plugins. The basic process is to throw logs at it, parse the message for the correct date, split the message into fields if desired, and forward the result to some indexer and search it using some frontend. Logstash scales vertically, and for larger volumes it's recommended to split the tasks of logshipping and log parsing to dedicated logstash instances. To avoid loosing logs when something goes down and to keep maintenance downtimes low, it's also recommended to put some message queue between the shipper(s) and the parser(s).

Redis fits exactly in that pictures, and acts as a key-value message queue in the pipeline. Logstash has a hard coded queue size of 20 events per configured input. If the queue fills up, the input gets blocked. Using a dedicated message queue instead is a good thing to have.

Graylog2 consits of a server and a webinterface. The server stores the logs in Elasticsearch, the frontend lets you search the indexes.

So, our whole pipeline looks like this:

logfiles  logstash shipper  redis  logstash indexer cluster  gelf  graylog2-server  elasticsearch cluster  graylog2-web-interface

Logstash is able to output to Elasticsearch directly, and there is the great Kibana frontend for it which is in many ways superior to graylog2-web-interface, but for reasons I explain at the end of the post we chose Graylog2 for weblogic logs.

Installation

The first step was to get graylog2, elasticsearch and mongodb up and running. We use RHEL 6, so this howto worked almost out of the box. I changed following:

  • latest stable elasticsearch-0.19.10
  • latest stable mongodb 2.2.0
  • default RHEL6 ruby 1.8.7 (so I left out any rvm stuff in that howto, and edited the provided scripts removing any rvm commands)

Prepare access to the logfiles for logstash

Next was to get logstash to index the logfiles correctly.

We decided to use SSHFS for mounting the logfile folders of all Weblogic instances onto a single box, and run the logstash shipper on that one using file input and output to redis. The reason for using SSHFS instead of installating logstash directly on the Weblogic machines and using for example a log4j appenders to logstash log4j inputs was mainly that our Weblogics are managed by a bank's data centre, so getting new software installed requires a lot work. The SSH access was already in place.

We have weblogic server logs (usually the weblogic.log), and each application generates a log4j-style logfile.

/data/logfiles/prod/server01/app1.log
/data/logfiles/prod/server01/app2.log
/data/logfiles/prod/server01/weblogic.log
/data/logfiles/prod/server02/app1.log
...
/data/logfiles/qsu/server01/app1.log
... and so on

This is the configuration file for the file-to-redis shipper. The only filter in place is the multiline filter, so that multiline messages get stored in redis as a single event already.

input {
  # server logs
  file {
    type => "weblogic-log"
    path => [ "/data/logfiles/*/*/weblogic.log" ]
  }
  # application logs
  file {
    type => "application"
    path => [ "/data/logfiles/*/*/planethome.log",
              "/data/logfiles/*/*/marktplatz*.log",
              "/data/logfiles/*/*/immoplanet*.log",
              "/data/logfiles/*/*/planetphone.log" ]
  }
}
filter {
  # weblogic server log events always start with ####
  multiline {
    type => "weblogic"
    pattern => "^####"
    negate => true
    what => "previous"
  }
  # application logs use log4j syntax and start with the year. So below will work until 31.12.2099
  multiline {
    type => "application"
    pattern => "^20"
    negate => true
    what => "previous"
  }
}
output {
  redis {
    host => "phewu01"
    data_type => "list"
    key => "logstash-%{@type}"
  }
}

And this is the config for the logstash parsers. Here the main work happens, logs get parsed, fileds get extracted. This is CPU intensive, so depending on the amount of messages, you can simply add more instances with the same config.

input { redis { type => "weblogic" host => "phewu01" data_type => "list" key => "logstash-weblogic" message_format => "json_event" } redis { type => "application" host => "phewu01" data_type => "list" key => "logstash-application" message_format => "json_event" } } filter { ################### # weblogic server logs ################### grok { # extract server environment (prod, uat, dev etc..) from logfile path  type => "weblogic" patterns_dir => "./patterns" match => ["@source_path", "%{PH_ENV:environment}"] } grok { type => "weblogic" pattern => ["####<%{DATA:wls_timestamp}> <%{WORD:severity}> <%{DATA:wls_topic}> <%{HOST:hostname}> <(%{WORD:server})?> %{GREEDYDATA:logmessage}"] add_field => ["application", "server"] } date { type => "weblogic" # joda-time doesn't know about localized CEST/CET (MESZ in German), # so use 2 patterns to match the date wls_timestamp => ["dd.MM.yyyy HH:mm 'Uhr' 'MESZ'", "dd.MM.yyyy HH:mm 'Uhr' 'MEZ'"] } mutate { type => "weblogic" # set the "Host" in graylog to the environment the logs come from (prod, uat, etc..) replace => ["@source_host", "%{environment}"] } ###################### # application logs ###################### # match and pattern inside one single grok{} doesn't work # also using a hash in match didn't work as expected if the field is the same, # so split this into single grok{} directives grok { type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_ENV:environment}"] } grok { # extract app name from logfile name type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_APPS:application}"] } grok { # extract node name from logfile path type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_SERVERS:server}"] } grok { type => "application" pattern => "%{DATESTAMP:timestamp} %{DATA:some_id} %{WORD:severity} %{GREEDYDATA:logmessage}" } date { type => "application" timestamp => ["yyyy-MM-dd HH:mm:ss,SSS"] } mutate { type => "application" replace => ["@source_host", "%{environment}"] } } output { gelf { host => "localhost" facility => "%{@type}" } }

In ./patterns there is a file containing 3 lines for the PH_ENV etc grok patterns to match.

I had several issues initially:

  • rsync to jumpbox and mounting to logserver via ssfhs would cause changes to go missing on some, but not all files
  • chaining rsyncs would cause some messages to be indexed with partial @message, as some files are huge and slow to transfer.
    • This was solved by mounting all logfile folders on the different environments directly with SSHFS, where possible.
    • The remaining rsync'ed files are rsync'ed with "--append --inplace" rsync parameters
  • indexing files would always start at position 0 of the file, over and over again
    • Only happened for rsync, using "--append --inplace" fixes this

Meanwhile I also took a look at Kibana, another great frontend to ElasticSearch. For the weblogic logs I'll keep Graylog2, as it allows saving predefined streams and provides that easy-to-use quickfilter, which eases up log crawling for our developers (they only want to search for a string in a timeframe - they also never made use of the power of Splunk). Also Kibana doesn't provide a way to view long stack traces in an acceptable fashion yet (cut message a n characters and provide a more link, something like that). But I added Apache logs in logstash, and those are routed to a logstash elasticsearch output and Kibana as WebUI. I'd really like to see some sort of merge between Kibana and Graylog2 and add saved searches to that mix - that would make a realy competitive Splunk alternative.


Posted by redkite
, |

logstash + graylog2 – cant ask more for logging

 
 
 
 
 
 
i
 
5 Votes

Quantcast

Everyone knows how important logging is for a web application. It is a shelter we build for the rainy day. But the logs in all the application has enormous amount of valuable information, that can give interesting perspectives about the application. Also as applications grow in complexity and scale, logs become spread across multiple machines and files. Soon developers/support people will be overwhelmed by the sheer number of log files to search and track issues. In order to overcome this situation, and to have a clear, simplified oversight over the system, a central logging system becomes necessary.

Was part of a team which was responsible for building a highly distributed and complex system. Just to give a idea of the kind of complexity involved, let me give a brief summary of tech components. The project was developed using three languages (1 dynamic and 2 static), uses sql and a nosql db, a queuing engine, etc.. In order to get the log consolidated and have a central view, we evaluated splunk. Unfortunately it was extremely costly. So we were forced to look at open source alternatives and finally we selected logstash and graylog.

Looking back at that decision, was one of the great decisions. I will share some insights into how logstash and graylog2 could be configured.

First we need to download the logstash jar to each of the machines where log files are generated.
Then we need to configure the input file for logstash to process. its pretty simple. we need to provide the path to files and also group them under different types.

1
2
3
4
5
6
input {
  file {
    type => nginx_web
    path => ["/opt/nginx/logs/access.log", "/opt/nginx/logs/error.log"]
  }
}

Graylog uses a log format called Graylog Extended Log Format(GELF). By using this format, we can send custom fields with the log. This format also doesnot have a log size limitation. We can preprocess the logs and define custom fields based on the line logged, before they are sent to the graylog server. Below is a example of nginx log being parsed using grok patterns(regular expressions) and fields are defined with the values matched. Grok patterns are extremely powerful, so they need a separate detailed blog… but thats for later.

1
2
3
4
5
6
filter {
 grok {
   type => nginx_web
   pattern => "%{IP:clientip} (?:%{HOST:clienthost}|-) (?:%{USER:clientuser}|-) \[%{HTTPDATE:time}\] \"(?:%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}|%{DATA:unparsedrq})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QUOTEDSTRING:httpreferrer} %{QUOTEDSTRING:httpuseragent}"
 }
}

The corresponding nginx log format is:

1
log_format  main  '$remote_addr $host $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $ssl_cipher $request_time';

Above grok filter will parse each log entry and fill the values for the following fields clientip, clienthost, clientuser, time, verb, request, httpversion, unparsedrq, response, bytes, httpreferrer, httpuseragent.

The advantage of splitting the input log entry into multiple fields, is that custom rules to search, group can be done on each of these fields in the graylog2 web.
Sample grok pattern for the rails 3 project is:

1
2
3
4
5
6
7
8
grok {
  type => app
  pattern => "\[%{WORD:requesttoken}\] \[%{IP:clientip}\] (?:%{DATA:logstmt}|-)"
}
grok {
  type => app
  pattern => "Rendered %{DATA:renderedtemplate} \(%{DATA:rendertime}\)"
}

The above grok filter parses the rails 3 app log and defines the following fields: requesttoken, clientip, logstmt, renderedtemplate, rendertime.

Next we need to configure the output. This is where we specify the output format as gelf and the graylog server to contact.
We can also specify custom fields. Here we are sending a custom field named environment with value as ‘uat’.
Another predefined field in gelf format is ‘facility’ and here we are setting it with the value of field ‘type’.

1
2
3
4
5
6
7
output {
 gelf {
 host => "graylog-server-ip"
 facility => "%{@type}"
 custom_fields => ["environment", "uat"]
 }
}

A complete sample configuration for logstash agent is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
input {
  file {
    type => pg91
    path => ["/var/lib/pgsql/9.1/pgstartup.log", "/var/lib/pgsql/9.1/data/pg_log/*.log"]
  }
  file {
    type => app
    path => ["/app/employeemgmt/shared/log/uat.log"]
  }
  file {
    type => nginx_web
    path => ["/opt/nginx/logs/access.log", "/opt/nginx/logs/error.log"]
  }
}
  
filter {
 grok {
   type => nginx_web
   pattern => "%{IP:clientip} (?:%{HOST:clienthost}|-) (?:%{USER:clientuser}|-) \[%{HTTPDATE:time}\] \"(?:%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}|%{DATA:unparsedrq})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QUOTEDSTRING:httpreferrer} %{QUOTEDSTRING:httpuseragent}"
 }
 grok {
   type => app
   pattern => "\[%{WORD:requesttoken}\] \[%{IP:clientip}\] (?:%{DATA:logstmt}|-)"
 }
 grok {
   type => app
   pattern => "Rendered %{DATA:renderedtemplate} \(%{DATA:rendertime}\)"
 }
}
  
output {
 gelf {
 host => "graylog-server-ip"
 facility => "%{@type}"
 custom_fields => ["environment", "uat"]
 }
}

All these configuration need to be done in a conf file.
Once the conf file is ready, we need to install the graylog2 server. Installation is pretty simple, again download the server jar file and run it. This graylog2 wiki will help you with that.
Finally we need to start the logstash agent using:

1
java -jar logstash-1.1.0-monolithic.jar agent -f logstash-agent.conf

Enjoy all your logs are in central Graylog2 server. Watch out for the next post on graylog2 web interface and how we can use it.

5 Responses to logstash + graylog2 – cant ask more for logging

  1. Nice article, concisely describes how to use logstash grok stuff. I was wondering how large your log volume is. And if you had any issues setting up elasticsearch to handle the volume. We have a stupid amount of log volume and had issues getting elasticsearch to handle it without building an elasticsearch cluster dedicated to logs.

    • boojapathy says:

      Elasticsearch occupies a pretty large space in order to store these logs. unfortunately the most easy solution is to build a elasticsearch cluster. But also you can look at logstash processing and leaving out unnecessary logs, for example load balancer health checks etc…

  2. Philipp says:

    can you expand your example in order to put the ssl_chiper and request_time in additional fields too?

    my logformat looks like this:
    ‘$host $remote_addr – $remote_user [$time_local] “$request” ‘
    ‘$status $body_bytes_sent “$http_referer” ‘
    ‘”$http_user_agent” “$http_x_forwarded_for” ‘
    ‘$ssl_cipher $request_time ‘
    ‘$gzip_ratio $upstream_addr $upstream_response_time’;

    I am not able to catch any field after http_user_agent :/

    This is my logstash filter
    “%{IPORHOST:host} %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] \”%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\” %{NUMBER:response} (?:%{NUMBER:bytes}|-) \”(?:%{URI:referrer}|-)\” %{QS:agent} %{QS:x_forwarded_for} %{USER:ssl_chiper} %{NUMBER:request_time} %{NUMBER:gzip_rato} %{IPORHOST:upstream} %{NUMBER:upstream_request_time}”

    • boojapathy says:

      Based on my understanding from the above log format, the “%{USER:ssl_chiper}” has to be replaced by “%{QUOTEDSTRING:ssl_chiper}”. In case, you are still having issues, can you post a sample line from the log file for which it is failing.

  3. Sharmith says:

    How to create a custom field and fill it with dynamic data from the log message.
    Sample log message given below. I want to add one field for “client IP” filled with client IP address, “Event ID” filled with event ID number in the below example “675″, “Username” filled with Username, “Service Name” filled with service name from the log.
    Your help on this is highly appreciated.
    Log:
    MSWinEventLog 1 Security 15596139 Mon Aug 06 11:21:48 2012 675 Security SYSTEM User Failure Audit XXXXX1 Account Logon Pre-authentication failed: User Name: xxxxxxxxx User ID: %{S-1-5-21-1058243859-2292328430-792808483-12929} Service Name: krbtgt/XXX Pre-Authentication Type: 0×0 Failure Code: 0×19 Client Address: 10.X.X.X 15534664

Posted by redkite
, |

virbr0 NAT 인터페이스 disable 시키기

왜 disable 시킬까?

 

by Vivek Gite · 0 comments

This entry is part 9 of 12 in the series Redhat KVM Virtulization

 

virtual network (virbr0)는 guest들이 네트웍 서비스에 접근하는 것을 허락하기위해서  Network address translation (NAT) 를 위해 사용된다. 하지만 NAT는 늦고 데스크탑 설치를 위해서 권장된다. 이 Network address translation (NAT)를 disable시키기 위해서는 아래와 같이 설정한다.

현재 설정상태 보기

아래와 같이 명령한다:

#ifconfig

 

결과 예제:

virbr0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:39 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:7921 (7.7 KiB)

 

또는 아래의 명령을 이용해라:

 

# virsh net-list

 

결과 예제:

Name State Autostart ----------------------------------------- default active yes

 

 

virbr0를 disable 시키는 방법:

# ifconfig

# virsh net-destroy default
# virsh net-undefine default
# service libvirtd restart

'02.서버-Linux' 카테고리의 다른 글

[리눅스]Find perm 옵션  (0) 2013.04.23
[리눅스]멀티 환경변수 case 문 이용  (0) 2013.03.29
[리눅스]RPM Failed dependencies  (0) 2013.03.28
[리눅스]NDD & TCPDUMP  (0) 2013.03.25
[리눅스]SoftWare RAID10  (0) 2013.03.18
Posted by redkite
, |

Graylog2 v0.10 Finally Released – Install on CentOS 6.3

So the much anticipated Graylog2 version 0.10 was released on the 14th, so I finally found some time to build a test box with all the new software and see how it compares to get up and running.

So let’s get started.

Only non-default repo I have installed is:

We are downloading the following software packages:

Download all the software: (http://www.graylog2.org/download)

A one liner for the lazy:

Just to make sure we got everything:

Extract everything:


Great now let’s get Ruby installed:

Great now let’s get Libyaml installed:

Install RVM (Ruby Version Manager):

 Once it’s done you need to source rvm to use it:

Check to make sure ruby is working and it can find the binary:

Install Ruby Gem Bundle:

Update System Gems:


 Installing Elastic Search:

 Install the ES service wrapper:

 Give yourself a control script:

 Give the ES cluster a unique name:

 Fire it up and test it:

 Should get a response similar to:

Add ElasticSearch to boot:


 Setup 10gen Repo and Install MongoDB:

Create the mongo db directory:

Mongo configure file create and start:

Wait for it to start, it takes a couple seconds:

Setup MongoDB and auth

Set MongoDB to start on boot:

Intall MongoDB Gem:


Install Graylog2-Server:

 Configure Graylog2.conf:

Configure at least these variables in /etc/graylog2.conf:

  • is_master = true
    • Set only one graylog2-server node as the master. This node will perform periodical and maintenance actions that slave nodes won’t. Every slave node will accept messages just as the master nodes. Nodes will fall back to slave mode if there already is a master in the cluster.
  • elasticsearch_config_file = /etc/graylog2-elasticsearch.yml
    • This is the path to the ElasticSearch configuration file for the built-in ElasticSearch node of graylog2-server. Your graylog2-server node will act as a node in your ElasticSearch cluster, but not store any data itself. It will distribute the writes to other nodes in the ElasticSearch cluster.
  • elasticsearch_max_docs_per_index = 20000000
    • How many log messages to keep per index. This setting multiplied withelasticsearch_max_number_of_indices results in the maximum number of messages in your Graylog2 setup. It is always better to have several more smaller indices than just a few larger ones.
  • elasticsearch_max_number_of_indices = 20
    • How many indices to have in total. If this number is reached, the oldest index will be deleted.
  • elasticsearch_shards = 4
    • The number of shards for your indices. A good setting here highly depends on the number of nodes in your ElasticSearch cluster. If you have one node, set it to 1. Read more about this in the knowledge base article about configuring and tuning ElasticSearch.
  • elasticsearch_replicas = 0
    • The number of replicas for your indices. A good setting here highly depends on the number of nodes in your ElasticSearch cluster. If you have one node, set it to 0. Read more about this in the knowledge base article about configuring and tuning ElasticSearch.
  • recent_index_ttl_minutes = 60
    • Graylog2 keeps a so called recent index that includes only the newest log messages. This allows fast overview pages in the web interface. The messages you see in the “show recent messages” view are from this index. If you have thousands of messages per minute, set it to 1 minute because there are so many new messages coming in. If you have just a few messages per minute, set it to a higher values to still have a good overview without having to click on “show all messages”.
  • mongodb_*
    • Enter your MongoDB connection and authentication information here. Make sure that you connect the web interface to the same database. You don’t need to configure mongodb_user and mongodb_password ifmongodb_useauth is set to false.

 

 The most important ones (the rest you can leave as default if you want):
  • processor_wait_strategy = blocking  (this helps load on the server by quite a bit)
  • mongodb_password = whatever password you set earlier
  • Take note of the AMQP Section we will come back to this later

Start up Graylog2-Server:

Note: You may see a couple snappy error messages the first time you start graylog2.  Just ignore them the first time as it’s having to setup all the indexes.
Wait until you get this message:

Open another SSH session and test it out and make sure it’s working:

You should see a whole bunch of output if it was successful.  If not you will receive something like:

Exit WebBrick:

Drop an init.d script to make it easy:

 Load it up:


Install Graylog2 Web Interface:

Fix the Gemfile:
Note:  The current version of Graylog2-Web-Interface uses json-1.5.5, unfortunately there is a royal pain in the butt issue of installing Ruby 2.0.0 and not having the ruby development headers to compile it.  To work around this issue we need to change the required version of json in the gemfile inside the graylog2-web-interface folder.
I also made some changes to the version of the mongo driver it’s using, as it was set to use a much older version (pretty sure the mongo, bson_ext part is optional)
Edit Gemfile inside graylog2-web-interface:

This is what my /usr/local/graylog2-web-interface/Gemfile looks like:


curl -L https://get.rvm.io | bash -s stable --autolibs=enabled --ruby --rails --trace   ### 안되면 이걸로 실행

rvm install 1.9.2 

Setup a Graylog2 User:

 Give root RVM access:

Setup the web interface’s mongo config:

 Start Graylog2 and setup your first user:

# Note: If mongo isn’t running, you used an @ symbol in your password or if you installed mongo from source or some other method, check /etc/mongod.conf and see where it is putting the database.  You may have to create /data/db directory, you will get an error that looks like this:

Open a browser and see if the web ui is working:


Install and configure Passenger:

Note: There is currently a bug with passenger-3.0.19 and ruby-2.0.0 if you run passenger-install-apache2-module you will get compilation errors. See this github issue

If they’ve fixed the passenger bug and you install a version > 3.0.19 then the below doesn’t apply otherwise you can use these steps as a workaround.
To work around the current issue with passenger-3.0.19 you can edit the gempacktask.rb inside the passenger gem:

Delete everything in it and paste the following into it (quick way to delete everything inside vim type: 1000 dd:

Now let’s install the apache module:

 Create passenger.conf for httpd:

Paste the text from the end of the passenger-apache2-module install:

 Set Permissions and Add Apache to startup and load:

Open a browser and see if the web ui is working:

Technically, you’ve got a working version of Graylog2 setup and working at this point.  If you wanted you could start forwarding syslog messages to the Graylog2 Server on port 514 and off you go.
If you would like to setup an AMQP broker so that messages can be queued and add a few useful features (restarting graylog2-server without losing syslog messages), read further and see how it’s setup.

Setup AMQP (RabbitMQ):
I’m going to be using RabbitMQ as our AMQP broker, you can use others if you wish.
Install RabbitMQ:


rabbitmq-server-3.1.0-1.noarch.rpm
Get RabbitMQAdmin:

 Start Rabbit and add to Startup:

Create RabbitMQ Users and Exchanges for Graylog to use, here is the link to the official docs for reference:RabbitMQ Management

Edit the graylog2.conf to enable AMQP:

Monitor the Graylog2.log file for this next part, as you will immediately see java errors if something isn’t setup right (ignore the plugin errors):

Go to the Graylog2 Web Interface > Settings > AMQP:
Add new configurations with these parameters there
  • Exchange: messages
  • Routing key: syslogudp
  • TTL: 720000
  • Type: syslog
If no errors in the graylog2.log file and the web ui says added successfully.  Look under Server Health on the web ui home page:

graylog2-AMQP


 Setup the new Graylog2-Radio: Official Documentation

Edit the init script, add the comments at the top for chkconfig and change a couple paths:

Edit the Graylog2-Radio Inputs:

Start Graylog2-Radio:

You can monitor the log file to see if its working at:

If everything is working correctly:

Add Graylog2-Radio to Startup:

Change rsyslog to forward to Graylog2 port:

At the very bottom of the file:

Of course this is by far the simplest method of getting all this working.  Some other things you can do is add more exchanges for your applications, just don’t forget to setup the corresponding nodes in the graylog2-web-interface and inside the graylog2-radio inputs config file.

I ran through this entire setup 3 times and I “think” I got all the errors, but if you run into anything please let me know!

Side note: Stream Dashboards seem broken in 0.10.2 of the web-interface


RabbitMQ 설치 관련 오류 

yum install libcom 설치    

RabbitMQ 설치 오류 메시지 처리 방법

Database Hang (/var/log/rabbitmq/startup_log) 
- /var/lib/rabbitmq/mnsia 디렉토리 삭제 후 재시작

Network Startup Failed

- rabbitmq could not start tcp listener 
- netstat -nlp 로 tcp 5672 사용 데몬 확인

As in most cases I'm sure, this issue was caused by a misunderstanding on my part. RHEL provides an amqp server called Qpid which was already running. Since I thought that epmd was running on 5672, I missed the listing for ampq/Qpid in
etstat (not a fan of symbolic ports in the 
output now).

Stopping the Qpid service corrects the problem.

# service qpidd stop & chkconfig --del qpidd



Client SYSLOG 연동 : 기본 시스로그로 연동 시 graylog2에서 host field 값에 프로세스명이 찍히는 버그 발생. 아래의 rsyslog 설치 후 셋팅 진행하도록 workarround.

/etc/rsyslog.conf:

$template GRAYLOG2,"<%PRI%>%HOSTNAME% %TIMESTAMP% %syslogtag% %APP-NAME% %msg%\n"
$ActionForwardDefaultTemplate GRAYLOG2
*.* @graylog-server

/etc/sysconfig/rsyslogd.conf

SYSLOGD_OPTIONS="-c2 -m 0 -r514"


Posted by redkite
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함