#1933 Actor and err trace

Akcelisto Fri 29 Jun 2012

Why actors do not print stack trace? This lead to redundant code.

const class MyActor : Actor{

  new make():super(ActorPool()){

  }

  override Obj? receive(Obj? msg){
    try{
      //...
    }catch(Err e){
      e.trace
      throw e
    }
  }
}

Akcelisto Fri 29 Jun 2012

Oops. Stack is printed. But there is case when not printed:

class TraceTest{
  Void main(){
    try{
      Json.json
    }catch(Err e){
      echo("proper stack")
      e.trace
    }
    try{
      a := MyActor()
      a.send(0).get
    }catch(Err e){
      echo("reduced stack")
      e.trace
    }
  }
}

class Json{
  static Str json(){
    d := Int:Int[:]
    d[0] = 0
    return JsonOutStream.writeJsonToStr(d)
  }
}

const class MyActor : Actor{
  static const ActorGames cur := ActorGames()

  new make():super(ActorPool()){

  }

  override Obj? receive(Obj? msg){
    if(msg==0){
      return Json.json()
    }
    return null
  }
}

proper stack
sys::CastErr: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
  fan.sys.Map.each (Map.java:347)
  util::JsonOutStream.writeJsonMap (JsonOutStream.fan:86)
  util::JsonOutStream.writeJson (JsonOutStream.fan:50)
  util::JsonOutStream.writeJsonToStr (JsonOutStream.fan:24)
  igruktorServer::JsonQ.json (TraceTest.fan:30)
  igruktorServer::TraceTest.main (TraceTest.fan:7)
  java.lang.reflect.Method.invoke (Unknown)
  fan.sys.Method.invoke (Method.java:559)
  fan.sys.Method$MethodFunc.callOn (Method.java:230)
  fan.sys.Method.callOn (Method.java:139)
  fanx.tools.Fan.callMain (Fan.java:175)
  fanx.tools.Fan.executeType (Fan.java:140)
  fanx.tools.Fan.execute (Fan.java:41)
  fanx.tools.Fan.run (Fan.java:298)
  fanx.tools.Fan.main (Fan.java:336)

reduced stack
sys::CastErr: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
  concurrent::Future.get (Future.java:100)
  concurrent::Future.get (Future.java:57)
  igruktorServer::TraceTest.main (TraceTest.fan:14)
  java.lang.reflect.Method.invoke (Unknown)
  fan.sys.Method.invoke (Method.java:559)
  fan.sys.Method$MethodFunc.callOn (Method.java:230)
  fan.sys.Method.callOn (Method.java:139)
  fanx.tools.Fan.callMain (Fan.java:175)
  fanx.tools.Fan.executeType (Fan.java:140)
  fanx.tools.Fan.execute (Fan.java:41)
  fanx.tools.Fan.run (Fan.java:298)
  fanx.tools.Fan.main (Fan.java:336)
  sys::CastErr: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
    concurrent::Actor._dispatch (Actor.java:236)
    concurrent::Actor._work (Actor.java:199)
    concurrent::ThreadPool$Worker.run (ThreadPool.java:255)

kaushik Sat 30 Jun 2012

Errors thrown out of actors are not printed until a "get". We have talked about this before but a solution to this will save time when debugging such code. maybe a flag on startup? Here's a simplified version

using concurrent
class ActorTest{
    Void main(){
        Actor(ActorPool()){
            throw Err()
        }.send(null)

        Actor.sleep(5sec)
    }
}

brian Sat 30 Jun 2012

A flag on startup for debug might be useful, but I don't think it would work in practice. In a real system, you might have 100s of exceptions getting thrown often as just normal flow of behavior. In most cases they are getting caught by client and handled. If you logged everyone one of those even with a flag I think it would be too noisy. The trick would be to figure out a way to log only those messages that don't get accessed by a Future.

SlimerDude Sat 30 Jun 2012

Okay, an admission of guilt - all my Actors extend the following:

const class AfActor : Actor {
  private const static Log log := Log.get("AfActor")

  new make(ActorPool pool, Str stashName) : super(pool) { }

  Obj? get(|Obj?->Obj?| f) {
    return send(f).get
  }

  override Obj? receive(Obj? msg) {
    func := (msg as |Obj?->Obj?|) 
    try {
      return func.call(this)
    } catch (Err e) {
      // if the func has a return type, then an the Err is rethrown on assignment 
      // else we log the Err so the Thread doesn't fail silently 
      if (func.returns == Void#)
        log.err("AfActor receive()", e)
      throw e
    } 
  }
}

meaning my Actors look like:

const class Pulsar : AfActor {
  Void stop() {
    send |->| {
      ...stuff...
    }
  }
}

so I can send / run / return code within the global thread space. But note my receive function logs errors if the calling function doesn't have a return value.

Steve.

Akcelisto Sun 1 Jul 2012

No. I writed not about err stack is printed only if get is called.

Look at my example code. I call get and stack is printed. But stack is reduced.

This depend on which type exception is throwed.

Login or Signup to reply.