<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -5,7 +5,9 @@ require &quot;optparse&quot;
 require File.dirname(__FILE__) + '/../lib/nanite'
 
 options = {:root =&gt; Dir.pwd,
-           :services =&gt; [] }
+           :services =&gt; [],
+           :log_level =&gt; 'info',
+           :ping_time =&gt; 15 }
 
 # Build a parser for the command line arguments
 opts = OptionParser.new do |opts|
@@ -46,14 +48,30 @@ opts = OptionParser.new do |opts|
   opts.on(&quot;-v&quot;, &quot;--vhost VHOST&quot;, &quot;This flag is for setting the rabbitmq vhost&quot;) do |vhost|
     options[:vhost] = vhost
   end
-  
+
   opts.on(&quot;-j&quot;, &quot;--json&quot;, &quot;This flag is for using JSON as the wire format rather then marshaled ruby objects&quot;) do |json|
     options[:format] = :json
   end
 
+  opts.on(&quot;-d&quot;, &quot;--daemonize&quot;, &quot;This flag is for run the nanite as a daemon&quot;) do |d|
+    options[:daemonize] = true
+  end
+  
+  opts.on(&quot;--ping-time PINGTIME&quot;, &quot;This flag is for setting the ping time, or how often the nanites contact the mappers&quot;) do |ping|
+    options[:ping_time] = ping
+  end
+
   opts.on(&quot;-s&quot;, &quot;--services SERVIVES&quot;, &quot;This flag is for setting the nanite's global services: -s /slice/42,/foo/3&quot;) do |res|
     options[:services] = res.split(/,/).map { |r| r.strip }
   end
+  
+  opts.on(&quot;-l&quot;, &quot;--log-level LEVEL&quot;, &quot;This flag is for setting the log level&quot;) do |level|
+    options[:log_level] = level
+  end
+  
+  opts.on(&quot;-a&quot;, &quot;--actor-threaded&quot;, &quot;This flag is will spawn actors in multi-threaded mode&quot;) do |res|
+    options[:threaded_actors] = true
+  end
 
 end
 </diff>
      <filename>bin/nanite</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,9 @@
-class Mock &lt; Nanite::Actor
-  expose :list
+class Clock &lt; Nanite::Actor
+  expose :time
     
-  def list(payload)
-    p &quot;got request&quot;
-    [1,2,3]
+  def time(payload)
+    Time.now
   end
 end
 
-Nanite::Dispatcher.register(Mock.new)
\ No newline at end of file
+Nanite::Dispatcher.register(Clock.new)
\ No newline at end of file</diff>
      <filename>examples/myagent/actors/mock.rb</filename>
    </modified>
    <modified>
      <diff>@@ -12,6 +12,7 @@ require 'nanite/marshal'
 require 'nanite/console'
 require 'extlib'
 require 'json'
+require 'logger'
 
 
 module Nanite
@@ -22,7 +23,9 @@ module Nanite
     attr_accessor :identity, :format, :status_proc, :results, :root, :vhost, :file_root, :files, :host
 
     attr_accessor :default_services, :last_ping, :ping_time
-
+  
+    attr_writer :log_level
+    
     include FileStreaming
 
     def send_ping
@@ -49,14 +52,30 @@ module Nanite
       rescue LoadError
       end
       Dir[&quot;#{Nanite.root}/actors/*.rb&quot;].each do |actor|
-        puts &quot;loading actor: #{actor}&quot;
+        Nanite.log.info &quot;loading actor: #{actor}&quot;
         require actor
       end
     end
+    
+    def log_level
+      @log_level || Logger::INFO
+    end
 
+    def levels
+      @levels ||= {
+        'fatal' =&gt; Logger::FATAL,
+        'error' =&gt; Logger::ERROR,
+        'warn'  =&gt; Logger::WARN,
+        'info'  =&gt; Logger::INFO,
+        'debug' =&gt; Logger::DEBUG 
+      }
+    end
+    
     def start(opts={})
       config = YAML::load(IO.read(File.expand_path(File.join(opts[:root], 'config.yml')))) rescue {}
       opts = config.merge(opts)
+
+      Nanite.log_level         = levels[opts[:Log_level]]
       Nanite.root              = opts[:root]
       Nanite.format            = opts[:format] || :marshal
       Nanite.identity          = opts[:identity] || Nanite.gensym
@@ -65,6 +84,8 @@ module Nanite
       Nanite.file_root         = opts[:file_root] || &quot;#{Nanite.root}/files&quot;
       Nanite.default_services  = opts[:services] || []
 
+      daemonize(opts[:log_file] || &quot;#{Nanite.identity}.log&quot;) if opts[:daemonize]
+
       AMQP.start :user  =&gt; opts[:user],
                  :pass  =&gt; opts[:pass],
                  :vhost =&gt; Nanite.vhost,
@@ -74,14 +95,20 @@ module Nanite
       load_actors
       advertise_services
 
-      EM.add_periodic_timer(15) do
+      EM.add_periodic_timer((opts[:ping_time]||15).to_i) do
         send_ping
       end
 
       Nanite.amq.queue(Nanite.identity, :exclusive =&gt; true).subscribe{ |msg|
-        Nanite::Dispatcher.handle(Nanite.load_packet(msg))
+        if opts[:threaded_actors]
+          Thread.new(msg) do |msg_in_thread|
+            Nanite::Dispatcher.handle(Nanite.load_packet(msg_in_thread))
+          end
+        else
+          Nanite::Dispatcher.handle(Nanite.load_packet(msg))
+        end
       }
-      start_console if opts[:console]
+      start_console if opts[:console] &amp;&amp; !opts[:daemonize]
     end
 
     def reducer
@@ -115,6 +142,15 @@ module Nanite
       @results ||= {}
     end
 
+    def log
+      @log ||= begin
+         log = Logger.new((Nanite.root||Dir.pwd) / &quot;nanite.#{Nanite.identity}.log&quot;)
+         log.level = Nanite.log_level
+         log
+      end
+      @log
+    end
+
     def gensym
       values = [
         rand(0x0010000),
@@ -127,5 +163,15 @@ module Nanite
       ]
       &quot;%04x%04x%04x%04x%04x%06x%06x&quot; % values
     end
+
+    protected
+    def daemonize(log_file)
+      exit if fork
+      Process.setsid
+      exit if fork
+      $stdin.reopen(&quot;/dev/null&quot;)
+      $stdout.reopen(log_file, &quot;a&quot;)
+      $stderr.reopen($stdout)
+    end
   end
 end</diff>
      <filename>lib/nanite.rb</filename>
    </modified>
    <modified>
      <diff>@@ -24,14 +24,18 @@ module Nanite
       def handle(packet)
         case packet
         when Nanite::Pong
+          Nanite.log.debug &quot;handling Pong: #{packet}&quot;
           Nanite.last_ping = Time.now
         when Nanite::Advertise
+          Nanite.log.debug &quot;handling Advertise: #{packet}&quot;
           Nanite.last_ping = Time.now
           Nanite.advertise_services
         when Nanite::Request
+          Nanite.log.debug &quot;handling Request: #{packet}&quot;
           result = dispatch_request(packet)
           Nanite.amq.queue(packet.reply_to).publish(Nanite.dump_packet(result)) if packet.reply_to
         when Nanite::Result
+          Nanite.log.debug &quot;handling Result: #{packet}&quot;
           Nanite.reducer.handle_result(packet)
         end
       end</diff>
      <filename>lib/nanite/dispatcher.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,10 +7,43 @@ module Nanite
 
     attr_accessor :mapper
 
+    # Make a nanite request which expects a response.
+    #
+    # ==== Parameters
+    # type&lt;String&gt;:: The dispatch route for the request
+    # payload&lt;Object&gt;:: Payload to send.  This will get marshalled en route
+    # 
+    # ==== Options
+    # :selector&lt;Symbol&gt;:: Method for selecting an actor.  Default is :least_loaded.
+    #   :least_loaded:: Pick the nanite which has the lowest load.
+    #   :all:: Send the request to all nanites which respond to the service.
+    #   :random:: Randomly pick a nanite.
+    #   :rr: Select a nanite according to round robin ordering.
+    # :timeout&lt;Numeric&gt;:: The timeout in seconds before giving up on a response.  
+    #   Defaults to 60.
+    # :target&lt;String&gt;:: Select a specific nanite via identity, rather than using
+    #   a selector.
+    #
+    # ==== Block Parameters
+    # :results&lt;Object&gt;:: The returned value from the nanite actor.
+    #
     def request(type, payload=&quot;&quot;, opts = {}, &amp;blk)
       Nanite.mapper.request(type, payload, opts,  &amp;blk)
     end
 
+    # Make a nanite request which does not expect a response.
+    #
+    # ==== Parameters
+    # type&lt;String&gt;:: The dispatch route for the request
+    # payload&lt;Object&gt;:: Payload to send.  This will get marshalled en route
+    # 
+    # ==== Options
+    # :selector&lt;Symbol&gt;:: Method for selecting an actor.  Default is :least_loaded.
+    #   :least_loaded:: Pick the nanite which has the lowest load.
+    #   :all:: Send the request to all nanites which respond to the service.
+    #   :random:: Randomly pick a nanite.
+    #   :rr: Select a nanite according to round robin ordering.
+    #
     def push(type, payload=&quot;&quot;, opts = {})
       Nanite.mapper.push(type, payload, opts)
     end
@@ -28,9 +61,6 @@ module Nanite
     end
 
     attr_accessor :nanites, :timeouts
-    def log *args
-      p args
-    end
 
     def initialize(ping_time)
       @identity = Nanite.gensym
@@ -39,7 +69,7 @@ module Nanite
       @amq = MQ.new
       @timeouts = {}
       setup_queues
-      log &quot;starting mapper with nanites(#{@nanites.keys.size}):&quot;, @nanites.keys
+      Nanite.log.info &quot;starting mapper with nanites(#{@nanites.keys.size}):\n#{@nanites.keys.join(',')}&quot;
       EM.add_periodic_timer(@ping_time) do
         check_pings
         EM.next_tick { check_timeouts }
@@ -87,7 +117,7 @@ module Nanite
     private
 
       def setup_queues
-        log &quot;setting up queues&quot;
+        Nanite.log.debug &quot;setting up queues&quot;
         @amq.queue(&quot;heartbeat#{@identity}&quot;,:exclusive =&gt; true).bind(@amq.fanout('heartbeat')).subscribe{ |ping|
           handle_ping(Nanite.load_packet(ping))
         }
@@ -114,7 +144,7 @@ module Nanite
         @nanites.each do |name, state|
           if (time - state[:timestamp]) &gt; @ping_time
             @nanites.delete(name)
-            log &quot;removed #{name} from mapping/registration&quot;
+            Nanite.log.info &quot;removed #{name} from mapping/registration&quot;
           end
         end
       end
@@ -123,7 +153,7 @@ module Nanite
         @nanites[reg.identity] = {:timestamp =&gt; Time.now,
                                   :services =&gt; reg.services,
                                   :status    =&gt; reg.status}
-        log &quot;registered:&quot;, reg.identity, @nanites[reg.identity]
+        Nanite.log.info &quot;registered: #{reg.identity}, #{@nanites[reg.identity]}&quot;
       end
 
       def least_loaded(res)
@@ -157,7 +187,7 @@ module Nanite
 
 
       def check_timeouts
-        puts &quot;checking timeouts&quot;
+        Nanite.log.debug &quot;checking timeouts&quot;
         time = Time.now
         @timeouts.each do |tok, timeout|
           if time &gt; timeout</diff>
      <filename>lib/nanite/mapper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -41,7 +41,7 @@ module FileStreaming
       when Nanite::FileChunk
         @dest.write(packet.chunk)
       when Nanite::FileEnd
-        puts &quot;file written: #{@dest}&quot;
+        Nanite.log.debug &quot;file written: #{@dest}&quot;
         @dest.close
         if cback = Nanite.callbacks[@domain]
           cback.call(@filename, packet.meta)
@@ -53,7 +53,7 @@ module FileStreaming
   end
 
   def subscribe_to_files(domain='global', &amp;blk)
-    puts &quot;subscribing to file broadcasts for #{domain}&quot;
+    Nanite.log.info &quot;subscribing to file broadcasts for #{domain}&quot;
     @files ||= {}
     Nanite.callbacks[domain] = blk if blk
     Nanite.amq.queue(&quot;files#{Nanite.identity}&quot;).bind(Nanite.amq.topic('file broadcast'), :key =&gt; &quot;nanite.filepeer.#{domain}&quot;).subscribe{ |packet|</diff>
      <filename>lib/nanite/streaming.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>dd5ffebb4b554f5c08de25343cb36ee1d7e6ead4</id>
    </parent>
    <parent>
      <id>6ca5dfa0328217ef8373c2256de766fc9f2fcef8</id>
    </parent>
  </parents>
  <author>
    <name>raggi</name>
    <email>jftucker@gmail.com</email>
  </author>
  <url>http://github.com/shift/nanite/commit/57e815749702e52cb6893fe73ea18f537de80caa</url>
  <id>57e815749702e52cb6893fe73ea18f537de80caa</id>
  <committed-date>2008-12-17T23:33:39-08:00</committed-date>
  <authored-date>2008-12-17T23:33:39-08:00</authored-date>
  <message>Merge branch 'master' of git://github.com/ezmobius/nanite

* 'master' of git://github.com/ezmobius/nanite:
  Added in config.yml and command line setting to spawn actors in multi-threaded mode
  document request
  document push
  Update README with a (painful) solution for rabbitmqctl dying with {badrpc,nodedown}
  make ping time a little more robust
  make ping time configurable
  added actual log levels
  updating nanite to support a true log file
  adding logger code so we log in the right place
  implemented nanite-daemonization support

Conflicts:

	lib/nanite.rb</message>
  <tree>66e515c18632f3e436e888a05712059d470130ff</tree>
  <committer>
    <name>raggi</name>
    <email>jftucker@gmail.com</email>
  </committer>
</commit>
