Is it ellegant to use a global variable to store a Logger object?

Hi, I use Logger class in a programm and since I need to log in lot of
different places (into classes, into methods...) I use a global variable in
this way:

  $log = Logger.new
  $log.debug ...

so I can use $log anywhere in the code. Is it ellegant and "the Ruby way"?

The other possibility I see is creating a class that stores the logger
instance into a @@class_variable (@@logger) and call class method anywhere in
the code:

  class MyLogger

    @@logger = Logger.new

    def self.debug(x)
      @@logger.debug(x)
    end

    ...
  end

  MyLogger.debug ...

Which is a more ellegant way? is there other option?

Thanks for any advice I could receive from you.

···

--
Iñaki Baz Castillo

Iñaki Baz Castillo wrote:

  $log = Logger.new
  $log.debug ...

The other possibility I see is

  class MyLogger

    @@logger = Logger.new

    def self.debug(x)
      @@logger.debug(x)
    end
  end

  MyLogger.debug ...

is there other option?

You could add a debug() method to the Kernel module:

module Kernel
  @@logger = Logger.new

  def debug message
    @@logger.debug message
  end
end

Then you could call it from anywhere in your code.

···

--
Posted via http://www.ruby-forum.com/\.

Iñaki Baz Castillo ha scritto:

Hi, I use Logger class in a programm and since I need to log in lot of different places (into classes, into methods...) I use a global variable in this way:

  $log = Logger.new
  $log.debug ...

so I can use $log anywhere in the code. Is it ellegant and "the Ruby way"?

The other possibility I see is creating a class that stores the logger instance into a @@class_variable (@@logger) and call class method anywhere in the code:

  class MyLogger

    @@logger = Logger.new

    def self.debug(x)
      @@logger.debug(x)
    end

    ...
  end

  MyLogger.debug ...

Which is a more ellegant way? is there other option?

Thanks for any advice I could receive from you.

Maybe and IMHO you can use a simple dependency injection pattern. You pass a Logger instance to the constructor of your classes. In this way you keep the logger object decoupled from other objects in the system. Moreover, testing will be easier (you can mock the logger implementation).

require 'logger'

class Container
  def logger
    @logger ||= Logger.new STDOUT
  end
  def foo
    Foo.new(logger)
  end
end

class Foo
  def initialize(logger)
    @logger = logger
  end
  def bar
    @logger.info('Foo#bar invoked.')
  end
end

c = Container.new
c.foo.bar

A bit offtopic:

If Ruby handled modules more like namespaces in C++ or similar
languages, a case such as 'log' would be trivial:

module MyModule
  def MyModule.log(a)
    puts a
  end
  class MyClass
    def func
      log("event") # => NoMethodError: Ruby doesn't search "parent"
modules
    end
  end
end

Similarly, Ruby doesn't search for "class" method like other
languages:

class MyClass
  def MyClass.log(a)
    puts a
  end
  def func
    log("event") # => NoMethoderror
  end
end

I am interested in rationale for this behaviour in Ruby. The examples
are intuitive, to me at least, and I'm curious what the reason is that
Ruby doesn't search for method in the class/parent module when an
instance method or doesn't exist in the class or included Module.

Lars

Iñaki Baz Castillo:

Hi, I use Logger class in a programm and since I need to log in lot
of different places (into classes, into methods...) I use a global
variable in this way:

  $log = Logger.new
  $log.debug ...

so I can use $log anywhere in the code.
Is it ellegant and "the Ruby way"?

One more elegant (IMHO) opinion, assuming you have a common namespace
(module) for your program, is to create a singleton with the below
approach:

module MyProgram
  class Logger
  class << self
    def debug …
      …
    end
  end
  end
end

This way the global namespace is not cluttered, there are no conflicts
with other programs’ Logger classes/objects, while anywhere in your
program (i.e., anywhere in module MyProgram) you can simply call

Logger.debug …

which is the clearest syntax to my eyes.

I have created a Config class with
this approach and it’s a joy to use:

do_something if Config.some_flag?

case Config.setting
when :value_a then do_a
when :value_b then do_b
when :value_c then do_c
end

(I’ve yet to hook Trollop to my Config class so that the command-line
options are nicely parsed and taken into account, but it’s on my todo.)

-- Shot

···

--
Only Irish coffee provides in a single glass all four essential
food groups: alcohol, caffeine, sugar, and fat. -- Alex Levine

Oh, interesting. Anyway let me a question:
How ellegant is using Kernel module? Imagine you are programming a framework
that others can use in their programms. Isn't dangerous to extend/modify
Kernel module since it will be shared by *all* the code?

Thanks a lot.

···

El Lunes, 23 de Junio de 2008, Suraj Kurapati escribió:

Iñaki Baz Castillo wrote:
> $log = Logger.new
> $log.debug ...
>
> The other possibility I see is
>
> class MyLogger
>
> @@logger = Logger.new
>
> def self.debug(x)
> @@logger.debug(x)
> end
> end
>
> MyLogger.debug ...
>
> is there other option?

You could add a debug() method to the Kernel module:

module Kernel
  @@logger = Logger.new

  def debug message
    @@logger.debug message
  end
end

Then you could call it from anywhere in your code.

--
Iñaki Baz Castillo

That's a cool solution :slight_smile:

···

El Martes, 24 de Junio de 2008, Andrea Fazzi escribió:

Iñaki Baz Castillo ha scritto:
> Hi, I use Logger class in a programm and since I need to log in lot of
> different places (into classes, into methods...) I use a global variable
> in this way:
>
> $log = Logger.new
> $log.debug ...
>
> so I can use $log anywhere in the code. Is it ellegant and "the Ruby
> way"?
>
> The other possibility I see is creating a class that stores the logger
> instance into a @@class_variable (@@logger) and call class method
> anywhere in the code:
>
>
> class MyLogger
>
> @@logger = Logger.new
>
> def self.debug(x)
> @@logger.debug(x)
> end
>
> ...
> end
>
> MyLogger.debug ...
>
> Which is a more ellegant way? is there other option?
>
> Thanks for any advice I could receive from you.

Maybe and IMHO you can use a simple dependency injection pattern. You
pass a Logger instance to the constructor of your classes. In this way
you keep the logger object decoupled from other objects in the system.
Moreover, testing will be easier (you can mock the logger implementation).

require 'logger'

class Container
  def logger
    @logger ||= Logger.new STDOUT
  end
  def foo
    Foo.new(logger)
  end
end

class Foo
  def initialize(logger)
    @logger = logger
  end
  def bar
    @logger.info('Foo#bar invoked.')
  end
end

c = Container.new
c.foo.bar

--
Iñaki Baz Castillo

Ok, this seems really ellegant and I've tested that I can
call "Logger.debug..." in any submodule/subclass into the program :slight_smile:

Just a question: Logger must use an instance of a class (real class Logger),
so to store it I think the best option is using a @@class_variable into
Logger module, something like:

module MyProgram
   class MyLogger
  @@logger = Logger.new(xxxxx,xxxx)
   class << self
     def debug(text)
          @@logger.debug(txt)
    end
   end
   end
end

Is it ok?
Thanks a lot.

···

El Jueves, 26 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

module MyProgram
class Logger
class << self
def debug …

end
end
end
end

This way the global namespace is not cluttered, there are no conflicts
with other programs’ Logger classes/objects, while anywhere in your
program (i.e., anywhere in module MyProgram) you can simply call

Logger.debug …

which is the clearest syntax to my eyes.

--
Iñaki Baz Castillo

Iñaki Baz Castillo wrote:

Imagine you are programming a framework
that others can use in their programms.
Isn't dangerous to extend/modify
Kernel module since it will be shared by *all* the code?

True. In that case, I would put the debug() method or the LOG object in
the top-level module of my library/framework:

# Using a debug() method
module FooBar
  module Logging
    @@logger = Logger.new

    def debug msg
      @@logger.debug msg
    end
  end

  class FooBar::Baz
    include Logging # <== NOTE this!

    def oh_no
      debug "oh no!"
    end
  end
end

# Using a LOG object
module FooBar
  LOG = Logger.new

  class FooBar::Baz
    def oh_no
      LOG.debug "oh no!"
    end
  end
end

···

--
Posted via http://www.ruby-forum.com/\.

I do not think so. Reasons: it clutters every instance with a
reference which can have a significant impact on memory if there are a
lot objects. Then, you have to change a class's #initialize signature
for all classes that do want to do logging and also manually code the
assignment inside the class. Accessing a logger from a global context
(whichever way you do it) saves memory and is less tedious.

Kind regards

robert

···

2008/6/24 Iñaki Baz Castillo <ibc@aliax.net>:

El Martes, 24 de Junio de 2008, Andrea Fazzi escribió:

require 'logger'

class Container
  def logger
    @logger ||= Logger.new STDOUT
  end
  def foo
    Foo.new(logger)
  end
end

class Foo
  def initialize(logger)
    @logger = logger
  end
  def bar
    @logger.info('Foo#bar invoked.')
  end
end

c = Container.new
c.foo.bar

That's a cool solution :slight_smile:

--
use.inject do |as, often| as.you_can - without end

Iñaki Baz Castillo:

module MyProgram
class Logger
class << self
def debug …

end
end
end
end

Ok, this seems really ellegant and I've tested that I can call
"Logger.debug..." in any submodule/subclass into the program :slight_smile:

:slight_smile:

Just a question: Logger must use an instance of a class (real
class Logger), so to store it I think the best option is using
a @@class_variable into Logger module

No – by using class << self, you’re operating on the Logger object
(an instance of the class Class), and you can access its *instance*
variables. That’s the other elegant part about this solution – you can
use anything you’re used to, including, for example, attr_accessors.

I use this approach like in the below code; I can use stuff like

$stderr.puts 'some debug line' if Config.debug

1.upto Config.max_pins do |pin|
  …
end

or decide whether to use Enumerable#map or the forkoff
gem based on whether Config.processes is one or more. :slight_smile:

shot@asterix:~/work/PhD/bzr/trunk$ cat lib/art-decomp/config.rb
module ArtDecomp class Config

class << self

  attr_accessor :debug, :processes, :qu_method, :qv_method, :silicone

  def init
    @debug = false
    @processes = 1
    @qu_method = :graph_merger
    @qv_method = :graph_merger
    @silicone = Set[Arch[4,2], Arch[5,1]]
  end

  def log string, run, runs, dawn
    left = ((Time.now - dawn)/run*(runs - run)).ceil
    $stderr << " [#{string} #{runs - run} #{left}s] " if Config.debug
  end

  def max_pins
    @silicone.map{|arch| arch.pins}.max
  end

  def max_pons
    @silicone.map{|arch| arch.pons}.max
  end

  alias reset init

end

end end

ArtDecomp::Config.init
shot@asterix:~/work/PhD/bzr/trunk$

-- Shot

···

El Jueves, 26 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

--
Smalltalk itself generates its own refactoring browser, test rig, IDE,
and 3D graphics subsystems as you write your program with it. So as you
structure your program, Smalltalk uses that structure to generate the
refactoring browser needed to refactor its structure. This is why some
advanced Smalltalk Gurus know the best way to program Smalltalk is to
simply pick up the CPU and shake it. -- Phlip, comp.programming

Iñaki Baz Castillo wrote:
> Imagine you are programming a framework
> that others can use in their programms.
> Isn't dangerous to extend/modify
> Kernel module since it will be shared by *all* the code?

True. In that case, I would put the debug() method or the LOG object in
the top-level module of my library/framework:

# Using a debug() method
module FooBar
  module Logging
    @@logger = Logger.new

    def debug msg
      @@logger.debug msg
    end
  end

  class FooBar::Baz
    include Logging # <== NOTE this!

    def oh_no
      debug "oh no!"
    end
  end
end

Humm, I don't like adding "include Logging" to every classes I use since
sometimes I use objects, sometimes classes, so I'd also need to "extend" some
classes not just "include".

# Using a LOG object
module FooBar
  LOG = Logger.new

  class FooBar::Baz
    def oh_no
      LOG.debug "oh no!"
    end
  end
end

Ok, in this case you use a constant (LOG). This is the same I do now but I use
a global variable ($log). Is more ellegant using a constant?

Thanks a lot.

···

El Lunes, 23 de Junio de 2008, Suraj Kurapati escribió:

--
Iñaki Baz Castillo

Could not agree more with you. May I add some other reasons.
This approach vioaltes principles we regard rather highly on this list
It is not DRY, you are really repeating yourself and in case of the
metaprogramming solutions you let Ruby repeat itself.
It is just much less simple than necessary.
You spread code dependencies all over the place, as a matter of fact
the expression "dependency injection" says it allready it is almost as
putting a virus (with constructive behavior) into your code, but can
you imagine how much more work refactoring will become?

My order of preference would be
1. $logger or $LOGGER
2. Logger

43. Kernel::log (or Object.log)

Cheers

···

On Wed, Jun 25, 2008 at 11:22 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

2008/6/24 Iñaki Baz Castillo <ibc@aliax.net>:

El Martes, 24 de Junio de 2008, Andrea Fazzi escribió:

require 'logger'

class Container
  def logger
    @logger ||= Logger.new STDOUT
  end
  def foo
    Foo.new(logger)
  end
end

class Foo
  def initialize(logger)
    @logger = logger
  end
  def bar
    @logger.info('Foo#bar invoked.')
  end
end

c = Container.new
c.foo.bar

That's a cool solution :slight_smile:

I do not think so. Reasons: it clutters every instance with a
reference which can have a significant impact on memory if there are a
lot objects. Then, you have to change a class's #initialize signature
for all classes that do want to do logging and also manually code the
assignment inside the class. Accessing a logger from a global context
(whichever way you do it) saves memory and is less tedious.

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

--
http://ruby-smalltalk.blogspot.com/

---
Les mêmes questions qu'on se pose
On part vers où et vers qui
Et comme indice pas grand-chose
Des roses et des orties.
-
Francis Cabrel

<snip>
Amen

grep --recursive '@@' lib && echo "Classvariables are the root of all evil ;)"

Cheers
Robert

···

On Fri, Jun 27, 2008 at 10:17 AM, Shot (Piotr Szotkowski) <shot@hot.pl> wrote:

Iñaki Baz Castillo:

El Jueves, 26 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

module MyProgram
  class Logger
  class << self
    def debug …
      …
    end
  end
  end
end

Ok, this seems really ellegant and I've tested that I can call
"Logger.debug..." in any submodule/subclass into the program :slight_smile:

:slight_smile:

Just a question: Logger must use an instance of a class (real
class Logger), so to store it I think the best option is using
a @@class_variable into Logger module

No – by using class << self, you're operating on the Logger object
(an instance of the class Class), and you can access its *instance*
variables.

Iñaki Baz Castillo:
>> module MyProgram
>> class Logger
>> class << self
>> def debug …
>> …
>> end
>> end
>> end
>> end
>
> Ok, this seems really ellegant and I've tested that I can call
> "Logger.debug..." in any submodule/subclass into the program :slight_smile:
>
:slight_smile:
:
> Just a question: Logger must use an instance of a class (real
> class Logger), so to store it I think the best option is using
> a @@class_variable into Logger module

No – by using class << self, you’re operating on the Logger object
(an instance of the class Class), and you can access its *instance*
variables.

Thanks, in fact I didn't understand the meaning of "class << self" until now.

That’s the other elegant part about this solution – you can
use anything you’re used to, including, for example, attr_accessors.

I use this approach like in the below code; I can use stuff like

$stderr.puts 'some debug line' if Config.debug

1.upto Config.max_pins do |pin|
  …
end

or decide whether to use Enumerable#map or the forkoff
gem based on whether Config.processes is one or more. :slight_smile:

This seems really cool. I'll try to use it.

Thanks a lot.

···

El Viernes, 27 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

> El Jueves, 26 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

--
Iñaki Baz Castillo

The only I don't like about the above code is the need of using .init method
explicitely. It could be nice if "initialize" would also work automatically
in some way, is not possible? (of course I understand that we are not
creating an instance here).

Thanks a lot.

···

El Viernes, 27 de Junio de 2008, Shot (Piotr Szotkowski) escribió:

module ArtDecomp class Config

class << self

attr_accessor :debug, :processes, :qu_method, :qv_method, :silicone

def init
@debug = false
@processes = 1
@qu_method = :graph_merger
@qv_method = :graph_merger
@silicone = Set[Arch[4,2], Arch[5,1]]
end

def log string, run, runs, dawn
left = ((Time.now - dawn)/run*(runs - run)).ceil
$stderr << " [#{string} #{runs - run} #{left}s] " if Config.debug
end

def max_pins
@silicone.map{|arch| arch.pins}.max
end

def max_pons
@silicone.map{|arch| arch.pons}.max
end

alias reset init

end

end end

ArtDecomp::Config.init

--
Iñaki Baz Castillo

Iñaki Baz Castillo wrote:

Humm, I don't like adding "include Logging" to every classes I use since
sometimes I use objects, sometimes classes, so I'd also need to "extend"
some classes not just "include".

You could use meta programming to include Logging in all nested classes
and modules of your top-level module:

module FooBar
  # ... code from previous e-mail ...

  # recursively adds Logging functionality to all nested classes
  extender = lambda do |k|
    k.constants.map {|c| k.const_get c }.
    select {|c| c.is_a? Class or c.is_a? Module }.
    each do |c|
      c.extend Logging
      extender[c]
    end
  end

  extender[self]
end

# Using a LOG object
module FooBar
  LOG = Logger.new

  class FooBar::Baz
    def oh_no
      LOG.debug "oh no!"
    end
  end
end

Ok, in this case you use a constant (LOG). This is the same I do now but
I use a global variable ($log). Is more ellegant using a constant?

Yes, in my opinion. A constant is constrained to the walls of your
library's top-level module, whereas a global variable is not.
Therefore, unless someone was modifying your library, they would not be
able to access your constant.

···

--
Posted via http://www.ruby-forum.com/\.

Could not agree more with you. May I add some other reasons.
This approach vioaltes principles we regard rather highly on this list
It is not DRY, you are really repeating yourself and in case of the
metaprogramming solutions you let Ruby repeat itself.
It is just much less simple than necessary.
You spread code dependencies all over the place, as a matter of fact
the expression "dependency injection" says it allready it is almost as
putting a virus (with constructive behavior) into your code, but can
you imagine how much more work refactoring will become?

Absolutely!

My order of preference would be
1. $logger or $LOGGER
2. Logger

43. Kernel::log (or Object.log)

Now, this really makes me wonder about the position before the last
one in that list...
:slight_smile:

Kind regards

robert

···

2008/6/25 Robert Dober <robert.dober@gmail.com>:

--
use.inject do |as, often| as.you_can - without end

Robert Dober ha scritto:

···

On Wed, Jun 25, 2008 at 11:22 AM, Robert Klemme > <shortcutter@googlemail.com> wrote:
  

2008/6/24 Iñaki Baz Castillo <ibc@aliax.net>:
    

El Martes, 24 de Junio de 2008, Andrea Fazzi escribió:
      

require 'logger'

class Container
  def logger
    @logger ||= Logger.new STDOUT
  end
  def foo
    Foo.new(logger)
  end
end

class Foo
  def initialize(logger)
    @logger = logger
  end
  def bar
    @logger.info('Foo#bar invoked.')
  end
end

c = Container.new
c.foo.bar
        

That's a cool solution :slight_smile:
      

I do not think so. Reasons: it clutters every instance with a
reference which can have a significant impact on memory if there are a
lot objects. Then, you have to change a class's #initialize signature
for all classes that do want to do logging and also manually code the
assignment inside the class. Accessing a logger from a global context
(whichever way you do it) saves memory and is less tedious.

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

Could not agree more with you. May I add some other reasons.
This approach vioaltes principles we regard rather highly on this list
It is not DRY, you are really repeating yourself and in case of the
metaprogramming solutions you let Ruby repeat itself.
It is just much less simple than necessary.
You spread code dependencies all over the place, as a matter of fact
the expression "dependency injection" says it allready it is almost as
putting a virus (with constructive behavior) into your code, but can
you imagine how much more work refactoring will become?

My order of preference would be
1. $logger or $LOGGER
2. Logger

43. Kernel::log (or Object.log)

Cheers

Hi Robert,

I would known if, in your opinion, DI is not DRY in general or you are referring to the particular case of logging. Moreover, which are alternative DRY solutions to DI that guarantees loose coupling between objects?

Andrea

It's not the first time I read this, but could I know a good reason for not
using @@class variables?

Thanks.

···

El Viernes, 27 de Junio de 2008, Robert Dober escribió:

grep --recursive '@@' lib && echo "Classvariables are the root of all evil
;)"

--
Iñaki Baz Castillo