블로그 이미지
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

달력

« » 2024.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
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함