<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,4 @@
 data
 doc/generated
+log
 tmp</diff>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -21,12 +21,14 @@ class Configuration
   attr_accessor :conf_dir
   attr_accessor :template_dir
   attr_accessor :static_dir
+  attr_accessor :log_dir
 
   # path of folder to store wiki app data in (this folder will be created)
   attr_accessor :data_dir
 
-  # logging level (:error, :warn, :info, :debug)
+  # logging level (:fatal &gt; :error &gt; :warn &gt; :info &gt; :debug), log file name
   attr_accessor :log_level
+  attr_accessor :log_file_name
 
   # automatically reload app when app files change? (for development)
   attr_accessor :auto_reload
@@ -46,9 +48,11 @@ class Configuration
     self.app_dir                = File.join(File.dirname(File.expand_path(__FILE__)), '../')
     self.conf_dir               = File.join(app_dir, 'conf')
     self.template_dir           = File.join(app_dir, 'templates')
-    self.data_dir               = File.join(app_dir, 'data')
     self.static_dir             = File.join(app_dir, 'static')
-    self.log_level              = :warn
+    self.log_dir                = File.join(app_dir, 'log')
+    self.data_dir               = File.join(app_dir, 'data')
+    self.log_level              = :info
+    self.log_file_name          = 'app.log'
     self.auto_reload            = false
     self.max_upload_filesize    = 200
   end
@@ -63,9 +67,9 @@ class Configuration
   def to_s
     [
       :app_name, :server_ip, :server_port, :master_repository_uri,
-      :sync_frequency, :user_name, :user_email, :app_dir, :conf_dir, 
-      :static_dir, :template_dir, :data_dir, :log_level, :auto_reload, 
-      :max_upload_filesize
+      :user_name, :user_email, :sync_frequency, :app_dir, :conf_dir,
+      :template_dir, :static_dir, :log_dir, :data_dir, :log_level,
+      :log_file_name, :auto_reload, :max_upload_filesize
     ].collect do |c|
       sprintf &quot;%12-s =&gt; %s&quot;, c.to_s, send(c).to_s
     end.join(&quot;\n&quot;)</diff>
      <filename>lib/configuration.rb</filename>
    </modified>
    <modified>
      <diff>@@ -122,7 +122,7 @@ module GitDb
         'remote.origin.url' =&gt; CONF.master_repository_uri
       }.each do |k, v|
         if (old = @git.config(k)) != v
-          log :info, &quot;Updating configuration: changing #{k} from '#{old}' to '#{v}'&quot;
+          log.info &quot;Updating GitDB configuration: Changing #{k} from '#{old}' to '#{v}'&quot;
           @git.config(k, v)
         end
       end</diff>
      <filename>lib/git_db.rb</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@
 # Ruby app server (just change the Rack handler in PicoFramwork::Server.start).
 #
 
-%w{ configuration rubygems rack fileutils tempfile mongrel }.each {|l| require l }
+%w{ configuration rubygems rack mongrel fileutils tempfile logger }.each {|l| require l }
 
 module PicoFramework
   # base controller class
@@ -26,7 +26,7 @@ module PicoFramework
 
     # 200: render template
     def render(template, context={})
-      log :info, &quot;Rendering #{template}&quot;
+      log.debug &quot;Rendering #{template}&quot;
       self.class.respond(200) do |out|
         inner = process_template(template, context)
         context.store(:inner, inner)
@@ -36,13 +36,13 @@ module PicoFramework
 
     # 303: redirect
     def redirect(uri)
-      log :info, &quot;Redirecting to #{uri}&quot;
+      log.debug &quot;Redirecting to #{uri}&quot;
       self.class.respond(303, { 'Location' =&gt; uri })
     end
 
     # respond plain-text
     def respond_plaintext(str, status=200)
-      log :info, &quot;Responding with '#{status}: #{str}'&quot;
+      log.debug &quot;Responding with '#{status}: #{str}'&quot;
       self.class.respond(status, { 'Content-Type' =&gt; 'text/plain' }) do |out|
         out.write str
       end
@@ -91,10 +91,10 @@ module PicoFramework
       end
 
       def extract_arguments(uri, regex)
-        log :debug, &quot;Extracting arguments from '#{uri}'&quot;
-        log :debug, &quot;  Attempting to match #{regex}&quot;
+        log.debug &quot;Extracting arguments from '#{uri}'&quot;
+        log.debug &quot;  Attempting to match #{regex}&quot;
         if m = regex.match(uri)
-          log :debug, &quot;    Found #{m.size - 1} arguments&quot;
+          log.debug &quot;    Found #{m.size - 1} arguments&quot;
           return m.to_a[1..-1].collect {|a| unescape(a) }
         end
         []
@@ -104,7 +104,7 @@ module PicoFramework
     # add the given controller instances to the routing table
     def add_controllers(controllers)
       @route_map ||= {}
-      log :info, &quot;Router: adding controllers to route map: #{controllers.join(',')}&quot;
+      log.debug &quot;Router: adding controllers to route map: #{controllers.join(',')}&quot;
       controllers.each { |c| c.routes.each {|r| @route_map[r] = c } }
       build_index
     end
@@ -118,20 +118,20 @@ module PicoFramework
     def process(uri)
       # check if necessary to auto-reload app on each request (if turned on in config)
       if CONF.auto_reload
-        log :debug, &quot;Checking if app needs to be reloaded&quot;
+        log.debug &quot;Checking if app needs to be reloaded&quot;
         RELOADER.reload_app
       end
 
       # routing
-      log :debug, &quot;Router: attempting to match #{uri}&quot;
+      log.debug &quot;Router: attempting to match #{uri}&quot;
       @routes.each do |r|
         regex = Router.regex(r)
-        log :debug, &quot;  Trying #{regex}&quot;
+        log.debug &quot;  Trying #{regex}&quot;
         if regex.match(uri)
           # route r is correct
           controller = @route_map[r]
           args = Router.extract_arguments(uri, regex)
-          log :debug, &quot;    Success! controller is #{controller}, args are #{args.join(', ')}&quot;
+          log.debug &quot;    Success! controller is #{controller}, args are #{args.join(', ')}&quot;
           return controller, args
         end
       end
@@ -149,14 +149,14 @@ module PicoFramework
 
     def call(env)
       begin
-        log :debug, 'Hit RequestHandler.call()'
+        log.debug 'Hit RequestHandler.call()'
 
         request = Rack::Request.new(env)
-        log :info, &quot;#{request.request_method} #{request.path_info}&quot;
+        log.debug &quot;#{request.request_method} #{request.path_info}&quot;
 
         controller, args = @router.process(request.path_info)
 
-        log :debug, &quot;Referrer: #{request.referrer}&quot;
+        log.debug &quot;Referrer: #{request.referrer}&quot;
 
         # TODO instead of injecting instance variables, can we use metaprogramming
         # to define get/post methods that have referrer and input as args?
@@ -175,7 +175,7 @@ module PicoFramework
           raise ArgumentError.new(&quot;Only GET and POST are supported, not #{request.request_method}&quot;)
         end
       rescue Router::NoPathFound
-        log :warn, &quot;No route found for '#{request.path_info}', returning 404.&quot;
+        log.warn &quot;No route found for '#{request.path_info}', returning 404.&quot;
         Controller.respond(404) do |out|
           out.write(&quot;&lt;pre&gt;404, baby. There ain't nothin' at #{request.path_info}.&lt;/pre&gt;&quot;)
         end
@@ -188,6 +188,12 @@ module PicoFramework
   class Server
     def initialize(addr, port, controller_module, static_dirs={})
       @addr, @port, @controller_module, @static_dirs = addr, port, controller_module, static_dirs
+
+      # initialize logger
+      FileUtils::mkdir_p CONF.log_dir
+      logger = Logger.new(File.join(CONF.log_dir, CONF.log_file_name))
+      logger.level = Logger.const_get(CONF.log_level.to_s.upcase)
+      PicoFramework.logger = logger
     end
 
     # set up the Rack stack to use (depends on configuration)
@@ -204,7 +210,7 @@ module PicoFramework
       app = Rack::URLMap.new({ '/' =&gt; main }.merge(static_dirs))
 
       # common middleware
-      app = Rack::CommonLogger.new(app)
+      app = Rack::CommonLogger.new(app, PicoFramework.logger)
       app = Rack::ShowExceptions.new(app)
 
       app
@@ -227,24 +233,13 @@ module PicoFramework
     end
   end
 
-  # simple logger
-  class Logger
-    class &lt;&lt; self
-      def log(level, msg)
-        if (log_level(CONF.log_level) &gt;= log_level(level))
-          puts &quot;[#{level.to_s.upcase}] #{msg}&quot;
-        end
-      end
-      
-      def log_level(level)
-        case level
-        when :error : 1
-        when :warn  : 2
-        when :info  : 3
-        when :debug : 4
-        else          5
-        end
-      end
+  class &lt;&lt; self
+    def logger=(new_logger)
+      @@logger = new_logger
+    end
+
+    def logger
+      @@logger
     end
   end
 end
@@ -263,14 +258,14 @@ def controller(*routes)
   c
 end
 
-# shorcut for easy logging
-def log(level, msg)
-  PicoFramework::Logger.log(level, msg)
+# shortcut to logger
+def log
+  PicoFramework.logger
 end
 
 # save some input (string, tempfile, etc) to the filesystem
 def save_file(input, destination)
-  log :debug, &quot;Saving #{input} to #{destination}&quot;
+  log.debug &quot;Saving #{input} to #{destination}&quot;
 
   # create the destination directory if it doesn't already exist
   dir = File.dirname(destination)</diff>
      <filename>lib/pico_framework.rb</filename>
    </modified>
    <modified>
      <diff>@@ -91,7 +91,7 @@ module Satellite
           save_file(input, filepath)
           GitDb.save(local_filepath, &quot;Satellite: saving #{name}&quot;)
         rescue GitDb::ContentNotModified
-          log :debug, &quot;Hunk.save(): #{name} wasn't modified since last save&quot;
+          log.debug &quot;Hunk.save(): #{name} wasn't modified since last save&quot;
         end
       end
 
@@ -383,7 +383,7 @@ module Satellite
       
       # process a file upload
       def process_upload
-        log :debug, &quot;Uploaded: #{@input}&quot;
+        log.debug &quot;Uploaded: #{@input}&quot;
         filename = @input['Filedata'][:filename].strip
 
         # save upload
@@ -410,7 +410,7 @@ module Satellite
             when Models::Upload
               &quot;/upload/#{escape(hunk.name)}/rename&quot;
             else
-              log :error, &quot;#{hunk} is neither a Page nor an Upload&quot;
+              log.error &quot;#{hunk} is neither a Page nor an Upload&quot;
               &quot;&quot;
             end
           end
@@ -421,7 +421,7 @@ module Satellite
             when Models::Upload
               &quot;/upload/#{escape(hunk.name)}/delete&quot;
             else
-              log :error, &quot;#{hunk} is neither a Page nor an Upload&quot;
+              log.error &quot;#{hunk} is neither a Page nor an Upload&quot;
               &quot;&quot;
             end
           end
@@ -556,7 +556,7 @@ module Satellite
     class SearchController &lt; controller '/search', &quot;/search\\?query=#{SEARCH_STRING}&quot;
       def get(query=nil)
         if query
-          log :debug, &quot;searched for: #{query}&quot;
+          log.debug &quot;searched for: #{query}&quot;
           results = Models::Page.search(query)
           render 'search', &quot;Searched for: #{query}&quot;, :query =&gt; query, :results =&gt; results
         else
@@ -596,24 +596,27 @@ module Satellite
 
   class &lt;&lt; self
     def sync
-      log :debug, &quot;Synchronizing with master repository.&quot;
+      log.info &quot;Synchronizing with master repository.&quot;
       begin
         GitDb.sync
       rescue GitDb::MergeConflict =&gt; e
         # TODO surface on front-end? already happens on page-load, though...
-        log :warn, &quot;Encountered conflicts during sync. The following files must be merged manually:&quot; +
+        log.warn &quot;Encountered conflicts during sync. The following files must be merged manually:&quot; +
           GitDb.conflicts.collect {|c| &quot;  * #{c}&quot; }.join(&quot;\n&quot;)
       rescue GitDb::ConnectionFailed
-        log :warn, &quot;Failed to connect to master repository during sync operation.&quot;
+        log.warn &quot;Failed to connect to master repository during sync operation.&quot;
       end
-      log :debug, &quot;Sync complete.&quot;
+      log.info &quot;Sync complete.&quot;
     end
 
-    def server
+    def create_server
       PicoFramework::Server.new(CONF.server_ip, CONF.server_port, Controllers, { '/uploads' =&gt; File.join(CONF.data_dir, Models::UPLOAD_DIR) })
     end
     
     def start
+      # first, create the server (this sets up the logger, among other things)
+      server = create_server
+
       # kill the whole server if an unexpected exception is encounted in the sync
       Thread.abort_on_exception = true
 </diff>
      <filename>lib/satellite.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a9907637d9a0ad83af31137713ca8c66aa810f89</id>
    </parent>
  </parents>
  <author>
    <name>Ken Pratt</name>
    <email>ken@kenpratt.net</email>
  </author>
  <url>http://github.com/kenpratt/satellite/commit/01114686eda4422607625970480f8792549f812b</url>
  <id>01114686eda4422607625970480f8792549f812b</id>
  <committed-date>2008-08-12T20:33:06-07:00</committed-date>
  <authored-date>2008-08-06T14:57:46-07:00</authored-date>
  <message>Refactored from custom logger to standard ruby logger, added log file.</message>
  <tree>3df19f555f5eea5bf12e34d7c00164988e664756</tree>
  <committer>
    <name>Ken Pratt</name>
    <email>ken@kenpratt.net</email>
  </committer>
</commit>
