1# The following was taken from github.com/crohr/syslogger and is BSD
2# licensed.
3require 'syslog'
4require 'logger'
5require 'thread'
6
7class Syslogger
8
9 VERSION = "1.6.0"
10
11 attr_reader :level, :ident, :options, :facility, :max_octets
12 attr_accessor :formatter
13
14 MAPPING = {
15 Logger::DEBUG => Syslog::LOG_DEBUG,
16 Logger::INFO => Syslog::LOG_INFO,
17 Logger::WARN => Syslog::LOG_WARNING,
18 Logger::ERROR => Syslog::LOG_ERR,
19 Logger::FATAL => Syslog::LOG_CRIT,
20 Logger::UNKNOWN => Syslog::LOG_ALERT
21 }
22
23 #
24 # Initializes default options for the logger
25 # <tt>ident</tt>:: the name of your program [default=$0].
26 # <tt>options</tt>:: syslog options [default=<tt>Syslog::LOG_PID | Syslog::LOG_CONS</tt>].
27 # Correct values are:
28 # LOG_CONS : writes the message on the console if an error occurs when sending the message;
29 # LOG_NDELAY : no delay before sending the message;
30 # LOG_PERROR : messages will also be written on STDERR;
31 # LOG_PID : adds the process number to the message (just after the program name)
32 # <tt>facility</tt>:: the syslog facility [default=nil] Correct values include:
33 # Syslog::LOG_DAEMON
34 # Syslog::LOG_USER
35 # Syslog::LOG_SYSLOG
36 # Syslog::LOG_LOCAL2
37 # Syslog::LOG_NEWS
38 # etc.
39 #
40 # Usage:
41 # logger = Syslogger.new("my_app", Syslog::LOG_PID | Syslog::LOG_CONS, Syslog::LOG_LOCAL0)
42 # logger.level = Logger::INFO # use Logger levels
43 # logger.warn "warning message"
44 # logger.debug "debug message"
45 #
46 def initialize(ident = $0, options = Syslog::LOG_PID | Syslog::LOG_CONS, facility = nil)
47 @ident = ident
48 @options = options || (Syslog::LOG_PID | Syslog::LOG_CONS)
49 @facility = facility
50 @level = Logger::INFO
51 @mutex = Mutex.new
52 @formatter = Logger::Formatter.new
53 end
54
55 %w{debug info warn error fatal unknown}.each do |logger_method|
56 # Accepting *args as message could be nil.
57 # Default params not supported in ruby 1.8.7
58 define_method logger_method.to_sym do |*args, &block|
59 return true if @level > Logger.const_get(logger_method.upcase)
60 message = args.first || block && block.call
61 add(Logger.const_get(logger_method.upcase), message)
62 end
63
64 unless logger_method == 'unknown'
65 define_method "#{logger_method}?".to_sym do
66 @level <= Logger.const_get(logger_method.upcase)
67 end
68 end
69 end
70
71 # Log a message at the Logger::INFO level. Useful for use with Rack::CommonLogger
72 def write(msg)
73 add(Logger::INFO, msg)
74 end
75
76 # Logs a message at the Logger::INFO level.
77 def <<(msg)
78 add(Logger::INFO, msg)
79 end
80
81 # Low level method to add a message.
82 # +severity+:: the level of the message. One of Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN
83 # +message+:: the message string.
84 # If nil, the method will call the block and use the result as the message string.
85 # If both are nil or no block is given, it will use the progname as per the behaviour of both the standard Ruby logger, and the Rails BufferedLogger.
86 # +progname+:: optionally, overwrite the program name that appears in the log message.
87 def add(severity, message = nil, progname = nil, &block)
88 if message.nil? && block.nil? && !progname.nil?
89 message, progname = progname, nil
90 end
91 progname ||= @ident
92
93 @mutex.synchronize do
94 Syslog.open(progname, @options, @facility) do |s|
95 s.mask = Syslog::LOG_UPTO(MAPPING[@level])
96 communication = clean(message || block && block.call)
97 if self.max_octets
98 buffer = "#{tags_text}"
99 communication.bytes do |byte|
100 buffer.concat(byte)
101 # if the last byte we added is potentially part of an escape, we'll go ahead and add another byte
102 if buffer.bytesize >= self.max_octets && !['%'.ord,'\\'.ord].include?(byte)
103 s.log(MAPPING[severity],buffer)
104 buffer = ""
105 end
106 end
107 s.log(MAPPING[severity],buffer) unless buffer.empty?
108 else
109 s.log(MAPPING[severity],"#{tags_text}#{communication}")
110 end
111 end
112 end
113 end
114
115 # Set the max octets of the messages written to the log
116 def max_octets=(max_octets)
117 @max_octets = max_octets
118 end
119
120 # Sets the minimum level for messages to be written in the log.
121 # +level+:: one of <tt>Logger::DEBUG</tt>, <tt>Logger::INFO</tt>, <tt>Logger::WARN</tt>, <tt>Logger::ERROR</tt>, <tt>Logger::FATAL</tt>, <tt>Logger::UNKNOWN</tt>
122 def level=(level)
123 level = Logger.const_get(level.to_s.upcase) if level.is_a?(Symbol)
124
125 unless level.is_a?(Fixnum)
126 raise ArgumentError.new("Invalid logger level `#{level.inspect}`")
127 end
128
129 @level = level
130 end
131
132 # Sets the ident string passed along to Syslog
133 def ident=(ident)
134 @ident = ident
135 end
136
137 # Tagging code borrowed from ActiveSupport gem
138 def tagged(*tags)
139 new_tags = push_tags(*tags)
140 yield self
141 ensure
142 pop_tags(new_tags.size)
143 end
144
145 def push_tags(*tags)
146 tags.flatten.reject{ |i| i.respond_to?(:empty?) ? i.empty? : !i }.tap do |new_tags|
147 current_tags.concat new_tags
148 end
149 end
150
151 def pop_tags(size = 1)
152 current_tags.pop size
153 end
154
155 def clear_tags!
156 current_tags.clear
157 end
158
159 protected
160
161 # Borrowed from SyslogLogger.
162 def clean(message)
163 message = message.to_s.dup
164 message.strip! # remove whitespace
165 message.gsub!(/\n/, '\\n') # escape newlines
166 message.gsub!(/%/, '%%') # syslog(3) freaks on % (printf)
167 message.gsub!(/\e\[[^m]*m/, '') # remove useless ansi color codes
168 message
169 end
170
171 private
172
173 def tags_text
174 tags = current_tags
175 if tags.any?
176 tags.collect { |tag| "[#{tag}] " }.join
177 end
178 end
179
180 def current_tags
181 Thread.current[:syslogger_tagged_logging_tags] ||= []
182 end
183end
184
185worker_processes 2
186working_directory ENV["GITLAB_PATH"]
187pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid"
188
189listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024
190
191timeout 60
192
193logger Syslogger.new
194
195preload_app true
196
197GC.respond_to?(:copy_on_write_friendly=) and
198 GC.copy_on_write_friendly = true
199
200check_client_connection false
201
202after_fork do |server, worker|
203 defined?(ActiveRecord::Base) and
204 ActiveRecord::Base.establish_connection
205end