Class: SemanticLogger::Appender::MongoDB

Inherits:
Base
  • Object
show all
Defined in:
lib/semantic_logger/appender/mongodb.rb

Overview

The Mongo Appender for the SemanticLogger

Mongo Document Schema:

_id        : ObjectId("4d9cbcbf7abb3abdaf9679cd"),
time       : ISODate("2011-04-06T19:19:27.006Z"),
host_name  : "Name of the host on which this log entry originated",
application: 'Name of application or service logging the data - clarity_base, nginx, tomcat',
pid        : process id
thread_name: "name or id of thread",
name       : "com.clarity.MyClass",
level      : 'trace|debug|info|warn|error|fatal'
level_index: 0|1|2|3|4|5
message    : "Message supplied to the logging call",
duration   : ms,  # Set by Logger#benchmark
tags       : "Some tracking id" | ["id1", "id2"]
payload : {
  Optional. Any user supplied data, including any thread specific context variables
  values supplied on a per log entry will override any thread context values
}
# When an exception is supplied as the first or second parameter
# If supplied as the first parameter, message='exception name'
exception: {
  name:        'MyException',
  message:     'Invalid value',
  stack_trace: []
}
# When a backtrace is captured
file_name: 'my_class.rb'
line_number: 42

Instance Attribute Summary collapse

Attributes inherited from Base

#formatter

Attributes inherited from Base

#filter, #name

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

colorized_formatter, #level

Methods inherited from Base

#benchmark, default_level, default_level=, #level, #level=, #payload, #pop_tags, #push_tags, #silence, #tagged, #tags, #with_payload

Constructor Details

#initialize(params = {}, &block) ⇒ MongoDB

Create a MongoDB Appender instance

SemanticLogger::Appender::MongoDB.new(db: Mongo::Connection.new['database'])

Parameters: :db [Mongo::Database]

The MongoDB database connection to use, not the database name

:collection_name [String]

Name of the collection to store log data in
Default: semantic_logger

:host_name [String]

host_name to include in the document logged to Mongo
Default: first part of host name extracted from Socket

:write_concern [Integer]

Write concern to use
see: http://docs.mongodb.org/manual/reference/write-concern/
Default: 1

:application [String]

Name of the application to include in the document written to mongo
Default: nil (None)

:collection_size [Integer]

 The size of the MongoDB capped collection to create in bytes
 Default: 1 GB

 Some examples
   Prod: 25GB (.5GB per day across 4 servers over 10 days)
   Dev: .5GB
   Test: File
   Release: 4GB

:collection_max [Integer]
  Maximum number of log entries that the capped collection will hold

:level [Symbol]
  Only allow log entries of this level or higher to be written to MongoDB

:filter [Regexp|Proc]
  RegExp: Only include log messages where the class name matches the supplied
  regular expression. All other messages will be ignored
  Proc: Only include log messages where the supplied Proc returns true
        The Proc must return true or false


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/semantic_logger/appender/mongodb.rb', line 85

def initialize(params={}, &block)
  @db              = params[:db] || raise('Missing mandatory parameter :db')
  @collection_name = params[:collection_name] || 'semantic_logger'
  @host_name       = params[:host_name] || Socket.gethostname.split('.').first
  @write_concern   = params[:write_concern] || 1
  @application     = params[:application]
  filter           = params[:filter]

  # Create a collection that will hold the lesser of 1GB space or 10K documents
  @collection_size = params[:collection_size] || 1024**3
  @collection_max  = params[:collection_max]

  reopen

  # Create the collection and necessary indexes
  create_indexes

  # Set the log level and formatter
  super(params[:level], filter, &block)
end

Instance Attribute Details

#applicationObject

Returns the value of attribute application.



37
38
39
# File 'lib/semantic_logger/appender/mongodb.rb', line 37

def application
  @application
end

#collectionObject (readonly)

Returns the value of attribute collection.



36
37
38
# File 'lib/semantic_logger/appender/mongodb.rb', line 36

def collection
  @collection
end

#collection_nameObject (readonly)

Returns the value of attribute collection_name.



36
37
38
# File 'lib/semantic_logger/appender/mongodb.rb', line 36

def collection_name
  @collection_name
end

#dbObject (readonly)

Returns the value of attribute db.



36
37
38
# File 'lib/semantic_logger/appender/mongodb.rb', line 36

def db
  @db
end

#host_nameObject

Returns the value of attribute host_name.



37
38
39
# File 'lib/semantic_logger/appender/mongodb.rb', line 37

def host_name
  @host_name
end

#write_concernObject

Returns the value of attribute write_concern.



37
38
39
# File 'lib/semantic_logger/appender/mongodb.rb', line 37

def write_concern
  @write_concern
end

Class Method Details

.host_nameObject

Default host_name to use if none is supplied to the appenders initializer



185
186
187
# File 'lib/semantic_logger/appender/mongodb.rb', line 185

def self.host_name
  @@host_name ||= Socket.gethostname.split('.').first
end

.host_name=(host_name) ⇒ Object

Override the default host_name



190
191
192
# File 'lib/semantic_logger/appender/mongodb.rb', line 190

def self.host_name=(host_name)
  @@host_name = host_name
end

.strip_colorizing(message) ⇒ Object

Strip the standard Rails colorizing from the logged message



180
181
182
# File 'lib/semantic_logger/appender/mongodb.rb', line 180

def self.strip_colorizing(message)
  message.to_s.gsub(/(\e(\[([\d;]*[mz]?))?)?/, '').strip
end

Instance Method Details

#create_indexesObject

Create the required capped collection Features of capped collection:

  • No indexes by default (not even on _id)

  • Documents cannot be deleted,

  • Document updates cannot make them any larger

  • Documents are always stored in insertion order

    • A find will always return the documents in their insertion order

Creates an index based on tags to support faster lookups



121
122
123
124
125
126
# File 'lib/semantic_logger/appender/mongodb.rb', line 121

def create_indexes
  options       = {capped: true, size: @collection_size}
  options[:max] = @collection_max if @collection_max
  db.create_collection(collection_name, options)
  db[@collection_name].ensure_index('tags')
end

#default_formatterObject

Default log formatter

Replace this formatter by supplying a Block to the initializer


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/semantic_logger/appender/mongodb.rb', line 145

def default_formatter
  Proc.new do |log|
    document               = {
      time:        log.time,
      host_name:   host_name,
      pid:         $$,
      thread_name: log.thread_name,
      name:        log.name,
      level:       log.level,
      level_index: log.level_index,
    }
    document[:application] = application if application
    document[:message]     = self.class.strip_colorizing(log.message) if log.message
    document[:duration]    = log.duration if log.duration
    document[:tags]        = log.tags if log.tags && (log.tags.size > 0)
    document[:payload]     = log.payload if log.payload
    if log.exception
      document[:exception] = {
        name:        log.exception.class.name,
        message:     log.exception.message,
        stack_trace: log.exception.backtrace
      }
    end
    if log.backtrace || log.exception
      backtrace              = log.backtrace || log.exception.backtrace
      location               = backtrace[0].split('/').last
      file, line             = location.split(':')
      document[:file_name]   = file
      document[:line_number] = line.to_i
    end
    document
  end
end

#flushObject

Flush all pending logs to disk.

Waits for all sent documents to be written to disk


139
140
141
# File 'lib/semantic_logger/appender/mongodb.rb', line 139

def flush
  db.get_last_error
end

#log(log) ⇒ Object

Log the message to MongoDB



195
196
197
198
199
200
201
202
# File 'lib/semantic_logger/appender/mongodb.rb', line 195

def log(log)
  # Ensure minimum log level is met, and check filter
  return false if (level_index > (log.level_index || 0)) || !include_message?(log)

  # Insert log entry into Mongo
  collection.insert(formatter.call(log), w: @write_concern)
  true
end

#purge_allObject

Purge all data from the capped collection by dropping the collection and recreating it. Also useful when the size of the capped collection needs to be changed



131
132
133
134
135
# File 'lib/semantic_logger/appender/mongodb.rb', line 131

def purge_all
  collection.drop
  @collection = nil
  create_indexes
end

#reopenObject

After forking an active process call #reopen to re-open open the handles to resources



108
109
110
# File 'lib/semantic_logger/appender/mongodb.rb', line 108

def reopen
  @collection = db[@collection_name]
end