Starting first with a classic application, and splitting the models/libs in to folders that are included/loaded.
When specifying the logger in the main file:
configure do
logfile = File.new("#{settings.root}/log/#{settings.environment}.log", 'a+')
logfile.sync = true
use Rack::CommonLogger, logfile
set :logger, Logger.new(logfile)
end
Calling logger.debug from a module or class returns NameError: undefined local variable or method `logger' for <Object or Module>
Can you show more code that clarifies what's in your modules and how you're including them in the main application?
Edit: shortcut to the actual Ruby code:
Here's the file that runs: https://github.com/Joshfindit/Sinatra-unexpected-logging-example/blob/master/SinatraApp/notesapp_sinatra.rb
And the folder it runs in: https://github.com/Joshfindit/Sinatra-unexpected-logging-example/tree/master/SinatraApp
There's a lot of code here, would it be possible for you to distill it into a smaller test case?
The essence is this:
notesapp_sinatra.rb brings in models with require_relative or load (tried both, and am open to suggestions)notesapp_sinatra.rb worksNameError above)Rack loggers are really only available in the request scope of the application, and Sinatra's logger helper method is only available within the Sinatra application class where logging was configured.
Sinatra's DSL and method delegation make it look like magic, but you have to remember that there is always a class (Sinatra::Application, or a subclass of Sinatra::Application or Sinatra::Base) behind the scenes holding the methods and behavior that make up a Sinatra application. Consider this simple example:
class Foo
def one; 1 end
end
class Bar
def two
one + one
end
end
Bar.new.two
Would you expect this to work? No, I hope not, because we haven't told Bar how to access Foo#one. The two classes and their instance methods are completely isolated from one another. This is a core tenant of Ruby and many other object-oriented programming languages. So you shouldn't expect Artefact#return_error_via_log to be able to access Sinatra::Application#logger, either!
You have a few options on how to proceed here. Probably the easiest and most common solution would be to create a separate logger to use in your models and wherever else. You can keep a handle to the logging object in a global or a constant, or use some dependency injection scheme. Then you have the option of either using that logger in your Sinatra application for requests and/or other messages or accepting Sinatra's default behavior.
Thank you for this comprehensive response.
This actually fills in a lot of other small gaps as I had assumed that Sinatra was the superclass of everything within classic applications.
Are there any straightforward examples that flesh out the different levels of Sinatra's scopes? Having whipped up a number of simple applications without any show-stoppers, it's just a matter of wrapping my head around this. The documentation looks good, but packed.
None that I know of. The documentation is the best resource. Yes, it is packed, but your understanding will deepen each time you read through it as you learn Sinatra.
Most helpful comment
Rack loggers are really only available in the request scope of the application, and Sinatra's
loggerhelper method is only available within the Sinatra application class where logging was configured.Sinatra's DSL and method delegation make it look like magic, but you have to remember that there is always a class (Sinatra::Application, or a subclass of Sinatra::Application or Sinatra::Base) behind the scenes holding the methods and behavior that make up a Sinatra application. Consider this simple example:
Would you expect this to work? No, I hope not, because we haven't told Bar how to access
Foo#one. The two classes and their instance methods are completely isolated from one another. This is a core tenant of Ruby and many other object-oriented programming languages. So you shouldn't expectArtefact#return_error_via_logto be able to accessSinatra::Application#logger, either!You have a few options on how to proceed here. Probably the easiest and most common solution would be to create a separate logger to use in your models and wherever else. You can keep a handle to the logging object in a global or a constant, or use some dependency injection scheme. Then you have the option of either using that logger in your Sinatra application for requests and/or other messages or accepting Sinatra's default behavior.