Skip to content
This repository has been archived by the owner on Dec 31, 2022. It is now read-only.

Commit

Permalink
feat(logrotate): support arbitrary logrotate customization
Browse files Browse the repository at this point in the history
Fixes #107
  • Loading branch information
nickmarden committed Aug 31, 2017
1 parent 639b03a commit fa95ab0
Show file tree
Hide file tree
Showing 10 changed files with 694 additions and 124 deletions.
37 changes: 35 additions & 2 deletions .kitchen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,50 @@ suites:
- recipe[opsworks_ruby::setup]
- recipe[opsworks_ruby::deploy]
attributes:
defaults:
global:
logrotate_template_owner: 'deploy'
logrotate_template_group: 'root'
logrotate_rotate: 75
framework:
logrotate_options:
- missingok
- notifempty
- copytruncate
- sharedscripts
logrotate_template_group: 'www-data'
webserver:
logrotate_options:
- missingok
- notifempty
- copytruncate
deploy:
other_project:
appserver:
adapter: 'unicorn'
database:
adapter: 'null'
framework:
adapter: 'rails'
assets_precompilation_command: '/bin/true'
appserver:
adapter: 'unicorn'
logrotate_name: 'dumber-app-logrotate'
logrotate_frequency: 'weekly'
logrotate_template_mode: '0750'
global:
logrotate_name: 'this-will-be-ignored'
logrotate_frequency: 'monthly'
logrotate_log_paths:
- /this/will/be/ignored1.log
webserver:
adapter: 'apache2'
logrotate_log_paths:
- /tmp/log1.log
- /tmp/log2.log
logrotate_options:
- missingok
- notifempty
logrotate_rotate: 15
logrotate_template_owner: 'root'
port: 8080
ssl_port: 8443
'ruby-ng':
Expand Down
4 changes: 4 additions & 0 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
default['defaults']['global']['purge_before_symlink'] = %w[log tmp/cache tmp/pids public/system public/assets]
default['defaults']['global']['rollback_on_error'] = true
default['defaults']['global']['logrotate_rotate'] = 30
default['defaults']['global']['logrotate_frequency'] = 'daily'
default['defaults']['global']['logrotate_options'] = %w[
missingok compress delaycompress notifempty copytruncate sharedscripts
]

# database
## common
Expand Down
84 changes: 84 additions & 0 deletions docs/source/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ Global parameters apply to the whole application, and can be used by any section
- **Type:** integer
- **Default:** ``30``
- **Important Notice:** The parameter is in days
- How many days of logfiles are kept.
- See Logrotate Attributes for more information on logrotate attribute precedence.

- ``app['global']['logrotate_frequency']``

- **Type:** string
- **Default:** ``daily``
- **Supported values:** ``daily``, ``weekly``, ``monthly``, ``size X``
- How often logrotate runs for the given log(s), either time-based or
when the log(s) reach a certain size.
- See Logrotate Attributes for more information on logrotate attribute precedence.

- ``app['global']['logrotate_options']``

- **Type:** Array
- **Default:** ``%w[missingok compress delaycompress notifempty copytruncate sharedscripts]``
- All of the unqualified options (i.e., without arguments) that should be enabled
for the specified logrotate configuration.
- See Logrotate Attributes for more information on logrotate attribute precedence.

- ``app['global']['logrotate_X']``

- **Type:** Varies
- Any attribute value Y for ``logrotate_X`` will cause the [logrotate_app](https://github.com/stevendanna/logrotate/blob/master/resources/app.rb)
resource _X_ to be called with argument Y. For example setting ``logrotate_cookbook`` to ``'my_cookbook'``
will result in the ``logrotate_app`` resource being invoked with the resource value ``cookbook 'my_cookbook'``.
- See Logrotate Attributes for more information on logrotate attribute precedence.


database
~~~~~~~~
Expand Down Expand Up @@ -223,6 +251,26 @@ framework

- A command which will be invoked to precompile assets.

- ``app['framework']['logrotate_name']``

- **Type:** string
- **Default:** Depends on adapter-specific behaviors
- The name of the logrotate_app resource, and generated configuration file,
for the specified app framework logrotate configuration.
- Unlike other logrotate attributes, this attribute can only be set or overridden
at a the app framework level; there are no app-wide or global settings beyond
those provided by the framework library

- ``app['framework']['logrotate_log_paths']``

- **Type:** Array
- **Default:** Depends on adapter-specific behaviors
- Which log file(s) should be backed up via logrotate. If this parameter evaluates
to an empty array, no logs will be backed up for the specified app framework.
- Unlike other logrotate attributes, this attribute can only be set or overridden
at a the app framework level; there are no app-wide or global settings beyond
those provided by the framework library.

padrino
^^^^^^^

Expand Down Expand Up @@ -427,6 +475,26 @@ webserver
override this setting as well to ensure that the opsworks_ruby cookbook
looks for the specified template in your cookbook.

- ``app['webserver']['logrotate_name']``

- **Type:** string
- **Default:** Depends on adapter-specific behaviors
- The name of the logrotate_app resource, and generated configuration file,
for the specified app webserver logrotate configuration.
- Unlike other logrotate attributes, this attribute can only be set or overridden
at a the app webserver level; there are no app-wide or global settings beyond
those provided by the webserver library

- ``app['webserver']['logrotate_log_paths']``

- **Type:** Array
- **Default:** Depends on adapter-specific behaviors
- Which log file(s) should be backed up via logrotate. If this parameter evaluates
to an empty array, no logs will be backed up for the specified app webserver.
- Unlike other logrotate attributes, this attribute can only be set or overridden
at a the app webserver level; there are no app-wide or global settings beyond
those provided by the webserver library

apache
^^^^^^

Expand Down Expand Up @@ -600,3 +668,19 @@ resque
.. |sidekiq.yml config file| replace:: ``sidekiq.yml`` config file
.. _sidekiq.yml config file: https://github.com/mperham/sidekiq/wiki/Advanced-Options#the-sidekiq-configuration-file

Logrotate Attributes
----------------------

Logrotate behaviors occur across multiple drivers, for example webserver and
framework. For this reason, the evaluation order for attribute-driven behaviors
is a bit more complex for logrotate than for other options that are either
entirely global (for example, ``global.environment``) or entirely isolated to a
single type of driver (``webserver.keepalive_timeout``).

The evaluation rules for logrotate setting _X_ are as follows, from highest
priority to lowest priority:

- ``app[driver_type]['logrotate_X']``
- ``app['global']['logrotate_X']``
- ``node['defaults'][driver_type]['logrotate_X']``
- ``node['defaults']['global']['logrotate_X']``
52 changes: 39 additions & 13 deletions libraries/drivers_dsl_logrotate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,58 @@ def log_paths(*log_paths)

def log_paths
self.class.log_paths.presence ||
(self.class.superclass.respond_to?(:log_paths) && self.class.superclass.log_paths)
(self.class.superclass.respond_to?(:log_paths) && self.class.superclass.log_paths) || []
end

def configure_logrotate
return if (log_paths || []).empty?
lr_path = logrotate_log_paths
lr_rotate = logrotate_rotate

context.logrotate_app "#{app['shortname']}-#{adapter}-#{deploy_env}" do
path lr_path
frequency 'daily'
rotate lr_rotate
options %w[missingok compress delaycompress notifempty copytruncate sharedscripts]
lr_path = logrotate_log_paths || []
return unless lr_path.any?
lr_props = logrotate_properties

context.logrotate_app logrotate_name do
path lr_path
lr_props.each { |k, v| send(k.to_sym, v) unless v.nil? }
end
end

def logrotate_name
evaluate_attribute('logrotate_name', app['shortname'], :app_driver) ||
[app['shortname'], adapter, deploy_env].compact.join('-')
end

def logrotate_log_paths
log_paths.map do |log_path|
lp = evaluate_attribute('logrotate_log_paths', app['shortname'], :app_driver) || log_paths
lp.map do |log_path|
next log_path.call(self) if log_path.is_a?(Proc)
next log_path if log_path.start_with?('/')
File.join(deploy_dir(app), log_path)
end.flatten.uniq
end

def logrotate_rotate
globals(:logrotate_rotate, app['shortname'])
# rubocop:disable Metrics/AbcSize
def logrotate_keys
all_keys =
(context.node['deploy'][app['shortname']].try(:[], driver_type).try(:keys) || []) +
(context.node['deploy'][app['shortname']].try(:[], 'global').try(:keys) || []) +
(context.node['defaults'][driver_type].keys || []) +
(context.node['defaults']['global'].keys || [])
all_keys.uniq.map { |k| Regexp.last_match(1) if k =~ /^logrotate_(.+)/ }.compact - %w[name log_paths]
end
# rubocop:enable Metrics/AbcSize

def logrotate_attribute(attribute)
%i[app_driver app_global default_driver default_global].map do |level|
evaluate_attribute(attribute, app['shortname'], level)
end.compact.first
end

def logrotate_properties
Hash[
logrotate_keys.map do |k|
lkey = "logrotate_#{k}"
[k, logrotate_attribute(lkey)]
end
]
end
end
end
Expand Down
19 changes: 16 additions & 3 deletions libraries/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,25 @@ def rdses
end

def globals(index, application)
globals = (node['deploy'][application].try(:[], 'global') || {}).symbolize_keys
return globals[index.to_sym] unless globals[index.to_sym].nil?
ag = evaluate_attribute(index, application, :app_global)
return ag unless ag.nil?

old_item = old_globals(index, application)
return old_item unless old_item.nil?
node['defaults']['global'][index.to_s]
evaluate_attribute(index, application, :default_global)
end

def evaluate_attribute(index, application, level)
case level
when :app_driver
node['deploy'].try(:[], application).try(:[], driver_type).try(:[], index.to_s)
when :app_global
node['deploy'].try(:[], application).try(:[], 'global').try(:[], index.to_s)
when :default_driver
node['defaults'].try(:[], driver_type).try(:[], index.to_s)
when :default_global
node['defaults'].try(:[], 'global').try(:[], index.to_s)
end
end

def old_globals(index, application)
Expand Down
Loading

0 comments on commit fa95ab0

Please sign in to comment.