Manage Keystone logs for MOS 7.0
This commit:
- separates the logstreamer for keystone-all.log between
MOS 6.1 and MOS 7.0 because in MOS 7.0 the HTTP response time is
reported in microseconds instead of seconds.
- creates a new logstreamer and decoder to parse logs produced by keystone
"main" and "admin".
Change-Id: Icb427d859b92a7365883b068364a3b269eda9be5
(cherry picked from commit fbcebd03d0
)
This commit is contained in:
parent
9baaee9601
commit
51eaadade6
|
@ -49,7 +49,16 @@ class { 'lma_collector::notifications::controller':
|
|||
}
|
||||
|
||||
# OpenStack logs are always useful for indexation and metrics collection
|
||||
class { 'lma_collector::logs::openstack': }
|
||||
|
||||
if hiera('fuel_version') == '7.0' {
|
||||
# With MOS 7.0, logs from keystone "main" and "admin" applications are not
|
||||
# copied in keystone-all.log. So we need to add a specific logger for them.
|
||||
# Also the format of keystone-all.log is different so we need to add a
|
||||
# specific treatment for it.
|
||||
class { 'lma_collector::logs::openstack_7_0': }
|
||||
} else {
|
||||
class { 'lma_collector::logs::openstack': }
|
||||
}
|
||||
|
||||
if ! $storage_options['objects_ceph'] {
|
||||
class { 'lma_collector::logs::swift': }
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
-- Copyright 2015 Mirantis, Inc.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
require "string"
|
||||
local l = require 'lpeg'
|
||||
l.locale(l)
|
||||
|
||||
local syslog = require "syslog"
|
||||
local patt = require 'patterns'
|
||||
local utils = require 'lma_utils'
|
||||
|
||||
local msg = {
|
||||
Timestamp = nil,
|
||||
Type = 'log',
|
||||
Hostname = nil,
|
||||
Payload = nil,
|
||||
Pid = nil,
|
||||
Fields = nil,
|
||||
Severity = nil,
|
||||
}
|
||||
|
||||
local pgname = {
|
||||
keystone_wsgi_admin_access = 'keystone-wsgi-admin',
|
||||
keystone_wsgi_main_access = 'keystone-wsgi-main',
|
||||
}
|
||||
|
||||
local syslog_pattern = read_config("syslog_pattern") or error("syslog_pattern configuration must be specified")
|
||||
local syslog_grammar = syslog.build_rsyslog_grammar(syslog_pattern)
|
||||
|
||||
local sp = l.space
|
||||
local dot = l.P'.'
|
||||
local quote = l.P'"'
|
||||
|
||||
local timestamp = l.Cg(patt.Timestamp, "Timestamp")
|
||||
local pid = l.Cg(patt.Pid, "Pid")
|
||||
local severity = l.Cg(patt.SeverityLabel, "SeverityLabel")
|
||||
local message = l.Cg(patt.Message, "Message")
|
||||
|
||||
local openstack_grammar = l.Ct(timestamp * sp * pid * sp * severity * sp * message)
|
||||
|
||||
-- Grammar for parsing HTTP response attributes from OpenStack logs
|
||||
local http_method = l.Cg(l.R"AZ"^3, "http_method")
|
||||
local url = l.Cg( (1 - sp)^1, "http_url")
|
||||
local http_version = l.Cg(l.digit * dot * l.digit, "http_version")
|
||||
-- Nova changes the default log format of eventlet.wsgi (see nova/wsgi.py) and
|
||||
-- prefixes the HTTP status, response size and response time values with
|
||||
-- respectively "status: ", "len: " and "time: ".
|
||||
-- Other OpenStack services just rely on the default log format.
|
||||
-- TODO(pasquier-s): build the LPEG grammar based on the log_format parameter
|
||||
-- passed to eventlet.wsgi.server similar to what the build_rsyslog_grammar
|
||||
-- function does for RSyslog.
|
||||
local http_status = l.P"status: "^-1 * l.Cg(l.digit^3, "http_status")
|
||||
local response_size = l.P"len: "^-1 * l.Cg(l.digit^1 / tonumber, "http_response_size")
|
||||
local response_time = l.P"time: "^-1 * l.Cg(l.digit^1 * dot^0 * l.digit^0 / tonumber, "http_response_time")
|
||||
local http_grammar = patt.anywhere(l.Ct(
|
||||
quote * http_method * sp * url * sp * l.P'HTTP/' * http_version * quote *
|
||||
sp * http_status * sp * response_size * sp * response_time
|
||||
))
|
||||
|
||||
local ip_address_grammar = patt.anywhere(l.Ct(
|
||||
l.Cg(l.digit^-3 * dot * l.digit^-3 * dot * l.digit^-3 * dot * l.digit^-3, "ip_address")
|
||||
))
|
||||
|
||||
function process_message ()
|
||||
local log = read_message("Payload")
|
||||
local m
|
||||
|
||||
msg.Fields = {}
|
||||
if utils.parse_syslog_message(syslog_grammar, log, msg) then
|
||||
m = openstack_grammar:match(msg.Payload)
|
||||
if m then
|
||||
if m.Pid then msg.Pid = m.Pid end
|
||||
if m.Timestamp then msg.Timestamp = m.Timestamp end
|
||||
msg.Payload = m.Message
|
||||
msg.Fields.severity_label = m.SeverityLabel
|
||||
end
|
||||
else
|
||||
return -1
|
||||
end
|
||||
|
||||
m = http_grammar:match(msg.Payload)
|
||||
if m then
|
||||
msg.Fields.http_method = m.http_method
|
||||
msg.Fields.http_status = m.http_status
|
||||
msg.Fields.http_url = m.http_url
|
||||
msg.Fields.http_version = m.http_version
|
||||
msg.Fields.http_response_size = m.http_response_size
|
||||
-- Since keystone is using Apache server the response time are
|
||||
-- in microseconds. We convert them into seconds.
|
||||
msg.Fields.http_response_time = m.http_response_time / 1e6
|
||||
m = ip_address_grammar:match(msg.Payload)
|
||||
if m then
|
||||
msg.Fields.http_client_ip_address = m.ip_address
|
||||
end
|
||||
end
|
||||
|
||||
-- Make programname consistent
|
||||
msg.Fields.programname = pgname[msg.Fields.programname] or msg.Fields.programname
|
||||
|
||||
inject_message(msg)
|
||||
return 0
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
-- Copyright 2015 Mirantis, Inc.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
require "string"
|
||||
|
||||
local l = require 'lpeg'
|
||||
l.locale(l)
|
||||
|
||||
local patt = require 'patterns'
|
||||
local syslog = require 'syslog'
|
||||
local utils = require 'lma_utils'
|
||||
|
||||
local msg = {
|
||||
Timestamp = nil,
|
||||
Type = 'log',
|
||||
Hostname = nil,
|
||||
Payload = nil,
|
||||
Pid = nil,
|
||||
Fields = nil,
|
||||
Severity = nil,
|
||||
}
|
||||
|
||||
local syslog_pattern = read_config("syslog_pattern") or error("syslog_pattern configuration must be specified")
|
||||
local syslog_grammar = syslog.build_rsyslog_grammar(syslog_pattern)
|
||||
|
||||
local timestamp = l.Cg(patt.Timestamp, "Timestamp")
|
||||
local sp = l.space
|
||||
local pid = l.Cg(patt.Pid, "Pid")
|
||||
local severity = l.Cg(patt.SeverityLabel, "SeverityLabel")
|
||||
local message = l.Cg(patt.Message, "Message")
|
||||
|
||||
local openstack_grammar = l.Ct(timestamp * sp * pid * sp * severity * sp * message)
|
||||
|
||||
-- This grammar is intended for log messages that are generated before RSYSLOG
|
||||
-- is fully configured
|
||||
local fallback_syslog_pattern = read_config("fallback_syslog_pattern")
|
||||
local fallback_syslog_grammar
|
||||
if fallback_syslog_pattern then
|
||||
fallback_syslog_grammar = syslog.build_rsyslog_grammar(fallback_syslog_pattern)
|
||||
end
|
||||
|
||||
function process_message ()
|
||||
local log = read_message("Payload")
|
||||
|
||||
if utils.parse_syslog_message(syslog_grammar, log, msg) or
|
||||
(fallback_syslog_grammar and utils.parse_syslog_message(fallback_syslog_grammar, log, msg)) then
|
||||
-- We are only interested by program named "main" and "admin"
|
||||
if (msg.Fields.programname == "main" or msg.Fields.programname == "admin") then
|
||||
msg.Fields.programname = "keystone-" .. msg.Fields.programname
|
||||
|
||||
local m = openstack_grammar:match(msg.Payload)
|
||||
if m then
|
||||
if m.Pid then msg.Pid = m.Pid end
|
||||
if m.Timestamp then msg.Timestamp = m.Timestamp end
|
||||
msg.Payload = m.Message
|
||||
msg.Fields.severity_label = m.SeverityLabel
|
||||
end
|
||||
|
||||
inject_message(msg)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
return -1
|
||||
end
|
|
@ -0,0 +1,96 @@
|
|||
# Copyright 2015 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
class lma_collector::logs::openstack_7_0 {
|
||||
include lma_collector::params
|
||||
include lma_collector::service
|
||||
|
||||
heka::decoder::sandbox { 'openstack':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
filename => "${lma_collector::params::plugins_dir}/decoders/openstack_log.lua" ,
|
||||
config => {
|
||||
syslog_pattern => $lma_collector::params::syslog_pattern
|
||||
},
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::decoder::sandbox { 'keystone_7_0':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
filename => "${lma_collector::params::plugins_dir}/decoders/keystone_7_0_log.lua" ,
|
||||
config => {
|
||||
syslog_pattern => $lma_collector::params::syslog_pattern
|
||||
},
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::decoder::sandbox { 'keystone_wsgi':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
filename => "${lma_collector::params::plugins_dir}/decoders/keystone_wsgi_log.lua" ,
|
||||
config => {
|
||||
syslog_pattern => $lma_collector::params::syslog_pattern
|
||||
},
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
# Use the <PRI> token as the delimiter because OpenStack services may log
|
||||
# messages with newlines and the configuration of the Syslog daemon doesn't
|
||||
# escape them.
|
||||
heka::splitter::regex { 'openstack':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
delimiter => '(<[0-9]+>)',
|
||||
delimiter_eol => false,
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::input::logstreamer { 'openstack_7_0':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
decoder => 'openstack',
|
||||
splitter => 'openstack',
|
||||
file_match => '(?P<Service>nova|cinder|glance|heat|neutron|murano)-all\.log$',
|
||||
differentiator => '[ \'openstack.\', \'Service\' ]',
|
||||
require => [Heka::Decoder::Sandbox['openstack'], Heka::Splitter::Regex['openstack']],
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::input::logstreamer { 'keystone_7_0':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
decoder => 'keystone_7_0',
|
||||
splitter => 'openstack',
|
||||
file_match => 'keystone-all\.log$',
|
||||
differentiator => '[ \'openstack.keystone\' ]',
|
||||
require => [Heka::Decoder::Sandbox['keystone_7_0'], Heka::Splitter::Regex['openstack']],
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::input::logstreamer { 'openstack_dashboard':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
decoder => 'openstack',
|
||||
file_match => 'dashboard\.log$',
|
||||
differentiator => '[ \'openstack.horizon\' ]',
|
||||
require => Heka::Decoder::Sandbox['openstack'],
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
|
||||
heka::input::logstreamer { 'keystone_wsgi':
|
||||
config_dir => $lma_collector::params::config_dir,
|
||||
decoder => 'keystone_wsgi',
|
||||
splitter => 'openstack',
|
||||
# We cannot use /var/log/keystone because it is owned by the keystone user.
|
||||
log_directory => '/var/log/',
|
||||
file_match => 'user\.log$',
|
||||
differentiator => '[ \'openstack.keystone\' ]',
|
||||
require => [Heka::Decoder::Sandbox['keystone_wsgi'], Heka::Splitter::Regex['openstack']],
|
||||
notify => Class['lma_collector::service'],
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue