Friday, August 7, 2009

A log4j adapter for Rails

This current client application I'm working on is a mixed bag of Ruby and Java parts. All our existing logging for the older Java parts uses log4j and we wanted to unify our Rails logging with that. I spent a couple of hours putting together this adapter we now use. If you need something similar it should give you a good place to start.



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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Log4jAdapter
include ActiveSupport::BufferedLogger::Severity
L4JLevel = org.apache.log4j.Level

SEVERETIES = {
DEBUG => L4JLevel::DEBUG,
INFO => L4JLevel::INFO,
WARN => L4JLevel::WARN,
ERROR => L4JLevel::ERROR,
FATAL => L4JLevel::FATAL,
}
INVERSE = SEVERETIES.invert

def initialize
@logger = org.apache.log4j.Logger.getLogger('com.shc.mmh.Rails')
@root = org.apache.log4j.Logger.getRootLogger
end

def add(severity, message = nil, progname = nil, &block)
message = (message || (block && block.call) || progname).to_s
@logger.log(SEVERETIES[severity], message)
end

def level
INVERSE[@logger.getEffectiveLevel]
end

def level=(level)
raise "Invalid log level" unless SEVERETIES[level.to_i]
@root.setLevel(SEVERETIES[level.to_i])
end

def enabled_for?(severity)
@logger.isEnabledFor(SEVERETIES[severity])
end

#Lifted from BufferedLogger
for severity in ActiveSupport::BufferedLogger::Severity.constants
class_eval <<-EOT, __FILE__, __LINE__
def
#{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
add(
#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
end # end
#
def
#{severity.downcase}? # def debug?
enabled_for?(
#{severity}) # DEBUG >= @level
end # end

EOT

end

def method_missing(meth, *args)
puts "UNSUPPORTED METHOD CALLED: #{meth}"
end
end

Wednesday, August 5, 2009

A Scala version of Unle Bob's lazy PI sequence in Clojure

I follow Uncle Bob on twitter and I'm also currently learning Scala. When I saw his tweet about a lazily evaluated infinite PI sequence in Clojure I couldn't resist giving it a shot in Scala. Here's my result (it works!). Feedback is absolutely welcome.



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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//Gives us the :: syntax for streams.  From http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient.
class RichStream[A](str: =>Stream[A]) {
def ::(hd: A) = Stream.cons(hd, str)
}
implicit def streamToRichStream[A](str: =>Stream[A]) = new RichStream(str)

object M { //Gives us a shorthand for declaring BigDecimals that Scala lacks
def apply(i:Int) = BigDecimal(i)
}

//Hack to work around poor bigdecimal support
val mc = new java.math.MathContext(300,java.math.RoundingMode.HALF_UP)
def divide(a:BigDecimal, b:BigDecimal) = {
new BigDecimal(a.bigDecimal.divide(b.bigDecimal, mc))
}

def piSummands(n: BigDecimal): Stream[BigDecimal] = {
divide(M(1), n) :: piSummands(n + M(2)).map(_ * -1)
}

def scaleStream(stream:Stream[BigDecimal], factor:Int) = {
stream map {_ * factor}
}

def addStreams(s1:Stream[BigDecimal], s2:Stream[BigDecimal]) = {
s1 zip(s2) map {z => z._1 + z._2}
}

def partialSums(s:Stream[BigDecimal]):Stream[BigDecimal] = {
s.head :: addStreams(s.tail, partialSums(s))
}

def piStream = scaleStream(partialSums(piSummands(1)), 4)

def square(s:BigDecimal) = s * s

def eulerTransform(s:Stream[BigDecimal]):Stream[BigDecimal] = {
val s0 = s(0)
val s1 = s(1)
val s2 = s(2)
val head = s2 - divide((square(s2 - s1)), ((s0 + (M(-2) * s1) + s2)))
head :: eulerTransform(s.tail)
}

type Transform = (Stream[BigDecimal]) => Stream[BigDecimal]

def makeTableau(transform: Transform, s:Stream[BigDecimal]):Stream[Stream[BigDecimal]] = {
s :: makeTableau(transform, transform(s))
}

def acceleratedSequence(transform:Transform, s:Stream[BigDecimal]) = {
makeTableau(transform, s) map {_.head}
}

val set = acceleratedSequence(eulerTransform, piStream)
println(set.take(150).last)

Monday, August 3, 2009

Rails threadsafe! and Engines

If you're planning to use the combination of engines and threadsafe! you'll need to do some extra work. Due to a bug in Rails the engine load paths are not added to the eager_load_paths at startup time. This makes engines unavailable in threadsafe! mode.

Fortunately, working around this problem is simple. Just subclass the plugin loader like this:



1
2
3
4
5
6
7
8
class EagerLoader < Rails::Plugin::Loader
def add_plugin_load_paths
super
engines.each do |engine|
configuration.eager_load_paths += engine.load_paths
end
end
end

And wire up your new loader in your environment.rb:



1
2
3
4
5
6
7
8
9
#require the plugin loader
require File.join(File.dirname(__FILE__), '..', 'lib', 'eager_loader')

Rails::Initializer.run do |config|
#override the default loader
config.plugin_loader = EagerLoader

# ...
end