Code update and class variables

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Code update and class variables

Holger Freyther
Hi all,

I am currently 'porting' (redoing) the OpenBSC/Osmocom logging framework in
Smalltalk and while developing I see that I have one question/issue with
updating the code.

I have a LogArea which is a three tuple of (description, enabled, minLevel), I
have a LogConfig that holds a list of areas and gives them local names.

So I have something like:

Object subclass: LogConfig [
        Config := LogConfig new.

        LogConfig class >> default [
                ^ Config
        ]

        addArea: anArea name: aName [
                addInstanceVariableAndSetIt
                GenerateGetMethod...
        ]
]

and in another Package/Namespace I would do..

log.LogConfig defaut addArea: localArea: #localName..


Now I have two issues:
        1.) 1 to 3: [SomeClass class addInstVarName: #boo], will add #boo
            three. Is that a bug? That should not be possible, bad things
            will happen as a result..
        2.) FileStream fileIn: 'Log.st'. will set Config back to a new
            instance of LogConfig and all added areas are gone. What are the
            workarounds? Put Config into the Smalltalk dict? Use Notifications
            so people can add their areas again?

thanks for the help

        z.

PS: I looked at Logging on squeaksource but I will need more.. different
areas, min debug level per area, context... e.g. only debug if this process is
handling data for this IMSI

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Paolo Bonzini-2
On Mon, Sep 6, 2010 at 09:11, Holger Hans Peter Freyther
<[hidden email]> wrote:

> Hi all,
>
> I am currently 'porting' (redoing) the OpenBSC/Osmocom logging framework in
> Smalltalk and while developing I see that I have one question/issue with
> updating the code.
>
> I have a LogArea which is a three tuple of (description, enabled, minLevel), I
> have a LogConfig that holds a list of areas and gives them local names.
>
> So I have something like:
>
> Object subclass: LogConfig [
>        Config := LogConfig new.
>
>        LogConfig class >> default [
>                ^ Config
>        ]
>
>        addArea: anArea name: aName [
>                addInstanceVariableAndSetIt
>                GenerateGetMethod...
>        ]
> ]
>
> and in another Package/Namespace I would do..
>
> log.LogConfig defaut addArea: localArea: #localName..

Passing note: namespaces are usually capitalized.

> Now I have two issues:
>        1.) 1 to 3: [SomeClass class addInstVarName: #boo], will add #boo
>            three. Is that a bug? That should not be possible, bad things
>            will happen as a result..

It's a bit ugly, but not strictly a bug.  I suggest you use a
dictionary, and #doesNotUnderstand: instead of a getter, especially
because you're adding the instance variables to _all_ instances of
LogConfig rather than just one.

>        2.) FileStream fileIn: 'Log.st'. will set Config back to a new
>            instance of LogConfig and all added areas are gone. What are the
>            workarounds? Put Config into the Smalltalk dict? Use Notifications
>            so people can add their areas again?

This would be fixed by using a dictionary and #doesNotUnderstand:, too.

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Holger Freyther
On 09/06/2010 04:30 PM, Paolo Bonzini wrote:

>
> It's a bit ugly, but not strictly a bug.  I suggest you use a
> dictionary, and #doesNotUnderstand: instead of a getter, especially
> because you're adding the instance variables to _all_ instances of
> LogConfig rather than just one.

Two more questions

1.) is it possible to only add instance variables only to one instance? How
would I do it? '123' addInstVarNamed didn't work here.

2.) #doesNotUnderstand will not work from what I see as the Logging Module
does not know who is going to add areas to it, unless I do something like
LogConfig allSubClassesDo: []... is that appropriate?


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Paolo Bonzini-2
On 09/06/2010 11:46 AM, Holger Hans Peter Freyther wrote:

> On 09/06/2010 04:30 PM, Paolo Bonzini wrote:
>> It's a bit ugly, but not strictly a bug.  I suggest you use a
>> dictionary, and #doesNotUnderstand: instead of a getter, especially
>> because you're adding the instance variables to _all_ instances of
>> LogConfig rather than just one.
>
> Two more questions
>
> 1.) is it possible to only add instance variables only to one instance? How
> would I do it? '123' addInstVarNamed didn't work here.

You need to create a "lightweight class", like

    | cl |
    cl := Behavior new.
    cl superclass: instance class.
    instance changeClassTo: cl.
    cl addInstVarNamed: 'a'.

However, it's broken and only works if "instance class" has no instance
variables at all.  I'll shortly push a fix.

> 2.) #doesNotUnderstand will not work from what I see as the Logging Module
> does not know who is going to add areas to it, unless I do something like
> LogConfig allSubClassesDo: []... is that appropriate?

I don't understand why would you subclass LogConfig rather than create
multiple instances?

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Holger Freyther
On 09/06/2010 06:24 PM, Paolo Bonzini wrote:


> However, it's broken and only works if "instance class" has no instance
> variables at all.  I'll shortly push a fix.

awesome! GNU Smalltalk is getting better and better, does anyone think a
windows version will help us to get more devs?

>
>> 2.) #doesNotUnderstand will not work from what I see as the Logging Module
>> does not know who is going to add areas to it, unless I do something like
>> LogConfig allSubClassesDo: []... is that appropriate?
>
> I don't understand why would you subclass LogConfig rather than create
> multiple instances?

Maybe my approach is wrong, so let me recap. I have multiple subsystems that
add their own areas but I want to write code like this anObject logDebug:
'message' area: #sccp. So for this I need to have a LogConfig per Process (or
one global one to start with).





_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Paolo Bonzini-2
On Mon, Sep 6, 2010 at 12:53, Holger Hans Peter Freyther
<[hidden email]> wrote:

>>> 2.) #doesNotUnderstand will not work from what I see as the Logging Module
>>> does not know who is going to add areas to it, unless I do something like
>>> LogConfig allSubClassesDo: []... is that appropriate?
>>
>> I don't understand why would you subclass LogConfig rather than create
>> multiple instances?
>
> Maybe my approach is wrong, so let me recap. I have multiple subsystems that
> add their own areas but I want to write code like this anObject logDebug:
> 'message' area: #sccp. So for this I need to have a LogConfig per Process (or
> one global one to start with).

Do you have a pointer to the API you're taking inspiration from?

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Holger Freyther
On 09/06/2010 07:09 PM, Paolo Bonzini wrote:

>
> Do you have a pointer to the API you're taking inspiration from?


Header File:

http://git.osmocom.org/gitweb?p=libosmocore.git;a=blob;f=include/osmocore/logging.h;h=7f33155a8330d5bc59d0262140ed3e8fea34050a;hb=HEAD

Implementation:
http://git.osmocom.org/gitweb?p=libosmocore.git;a=blob;f=src/logging.c;h=5be4e58ed485837dca221a6f0f3f48387e7620ca;hb=HEAD

Config/Setup:
http://openbsc.osmocom.org/trac/browser/openbsc/src/bsc_hack.c#L223

(create a target to log to stderr, initialize the area used by the app,
 allow everything to pass the filter)

Filter/Context setup:
http://openbsc.osmocom.org/trac/browser/openbsc/src/abis_rsl.c#L125


The framework is working good in OpenBSC. With the different targets we can
enable to log to our telnet interface (VTY from quagga), but only log messages
related to a specific subscriber (e.g. doing call testing and only want to see
my own messages).

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Paolo Bonzini-2
On Tue, Sep 7, 2010 at 03:45, Holger Hans Peter Freyther
<[hidden email]> wrote:
> Header File:
> http://git.osmocom.org/gitweb?p=libosmocore.git;a=blob;f=include/osmocore/logging.h;h=7f33155a8330d5bc59d0262140ed3e8fea34050a;hb=HEAD

Ok, so...

  73 struct log_target {
  74         struct llist_head entry;
  75
  76         int filter_map;
  77         void *filter_data[LOG_MAX_FILTERS+1];
  78
  79         struct log_category categories[LOG_MAX_CATEGORY+1];
  80         uint8_t loglevel;
  81         int use_color:1;
  82         int print_timestamp:1;
  83
  84         union {
  85                 struct {
  86                         FILE *out;
  87                         const char *fname;
  88                 } tgt_file;
  89
  90                 struct {
  91                         int priority;
  92                 } tgt_syslog;
  93
  94                 struct {
  95                         void *vty;
  96                 } tgt_vty;
  97         };
  98
  99         void (*output) (struct log_target *target, const char *string);
 100 };

I would not be too fussy about reproducing the exact characteristics of the API.

I guess subsys is what you called "area".

The basic hierarchy here is

LogEntry (simple struct: subsys/level/context replacing file+line/string)
LogTarget (methods create LogEntry and pass it to an abstract method)
    LogFilter (see below)
    LogFile (better: LogStream?)
    LogSyslog

LogFilters wrap another LogTarget and only pass through items in a
select category.  You can have class methods to create commonly used
filters, or you can make a subhierarchy like

    LogFilter (abstract)
        LogAreaFilter (enable one area or disable one area)
            LogEnableAreaFilter
            LogDisableAreaFilter
        LogLogicFilter
            LogAndFilter
            LogOrFilter
            LogNotFilter
        LogLevelFilter
        LogPluggableFilter

but that can come later.

LogTarget class methods can be used to set a default logging target
and, as you mentioned, you could have also a per-process LogTarget.

You can add a LogMultiplexer class to emulate
log_add_target/log_del_target.  It can be just an internal detail.

How does this look?

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Holger Freyther
On 09/07/2010 04:23 PM, Paolo Bonzini wrote:


> LogTarget class methods can be used to set a default logging target
> and, as you mentioned, you could have also a per-process LogTarget.
>
> You can add a LogMultiplexer class to emulate
> log_add_target/log_del_target.  It can be just an internal detail.
>
> How does this look?

Thanks for taking the time, the LogFilter hierachy is a nice idea. One reason
to have the dedicated 'LogArea' class is from a configuration point of view.

A user does not want to reconfigure the LogTarget (and the filters applied on
it) but he wants to see the SCCP messages. So currently on the telnet
interface I do something like:

        logging SCCP enabled.

With the filtering I would have to add an allow filter, or remove from the
target which is certainly possible but a bit of a hassle. On the other hand by
having a nice chain of filters one can do a lot more.


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Code update and class variables

Paolo Bonzini-2
On 09/07/2010 10:53 AM, Holger Hans Peter Freyther wrote:

> On 09/07/2010 04:23 PM, Paolo Bonzini wrote:
>
>
>> LogTarget class methods can be used to set a default logging target
>> and, as you mentioned, you could have also a per-process LogTarget.
>>
>> You can add a LogMultiplexer class to emulate
>> log_add_target/log_del_target.  It can be just an internal detail.
>>
>> How does this look?
>
> Thanks for taking the time, the LogFilter hierachy is a nice idea. One reason
> to have the dedicated 'LogArea' class is from a configuration point of view.
>
> A user does not want to reconfigure the LogTarget (and the filters applied on
> it) but he wants to see the SCCP messages. So currently on the telnet
> interface I do something like:
>
> logging SCCP enabled.
>
> With the filtering I would have to add an allow filter, or remove from the
> target which is certainly possible but a bit of a hassle. On the other hand by
> having a nice chain of filters one can do a lot more.

Yeah, maybe the LogFilter hierarchy sacrifices usability too much.  It's
nice to be able to modify the filter.  Maybe you can make instead a
hierarchy with LogFilter on the side instead of under LogTarget:

     LogEntry
     LogPolicy (abstract)
         LogFilter (implements a dynamically-changeable filter)
     LogTarget
         LogFile
         LogSyslog
         LogMultiplexer

Then every LogTarget has a LogPolicy and you can send messages like

    LogTarget>>policy
        ^policy ifNil: [policy := self defaultPolicy]

    LogTarget>>defaultPolicy
        ^LogFilter new
            minimumLevel: LogEntry error;
            yourself

    LogTarget default policy
        disable: #SCCP.
    LogTarget processDefault policy
        enable: #SCCP minimumLevel: LogEntry all.

Then LogTarget's logging method would have to create LogEntry, test it
against its LogFilter, and if successful pass it to the abstract method.

Another idea: LogPolicies could make a chain and, if the object
specifies neither enable nor disable, it could delegate to the next
policy.  So for example the process-default policy could delegate to the
global policy.  This delegation could be implemented in the abstract class.

     LogPolicy>>accept: anEntry
         (self shouldAccept: anEntry) ifTrue: [^true].
         (self shouldRejept: anEntry) ifTrue: [^false].
         ^self next isNil
             ifTrue: [true]
             ifFalse: [self next accept: anEntry]

     LogPolicy>>shouldAccept: anEntry
          self subclassResponsibility

     LogPolicy>>shouldReject: anEntry
          self subclassResponsibility

     LogTarget>>defaultPolicy
         | policy |
         policy := LogFilter new
            minimumLevel: LogEntry error;
            yourself.

         self == self class default
             ifFalse: [policy next: self class default policy].
         ^policy


(BTW, LogMultiplexer can have its own policy, which is combined
(logically by an AND) with its targets' policies).

Does this look nicer?

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk