log in non sidekiq class - ruby

I have a worker that delegates the work to another class like this:
class SynJob
include Sidekiq::Worker
sidekiq_options queue: :sync
def perform(user_id)
OtherClass.new(blah, blah, blah)
end
end
class OtherClass
def initialize
puts "we are in OtherClass"
end
end
My question is, how do I log to stdout from OtherClass.
My puts statements do not show up in the heroku stdout log.

The literal answer to your question is to use puts or other Ruby APIs for writing to stdout. You can call this both in your SynJob or your OtherClass code and it will execute the same, writing to the stdout of the sidekiq worker process.
However, this probably is not what you want to do. If this is a Rails app, you probably want to write to the Rails logger, which should be available both in your worker and in other code:
Rails.logger.info "I'm a debug message"
This will show up in the appropriate log both locally and when running deployed on Heroku.

Related

Using mixins during code parsing in Ruby

I want my Configurable module to include a config command to whatever app includes it.
edit: see the update on my reasoning a little further down
I get that error:
cli.rb:2:in '<module:Configurable>': undefined method 'desc' for Configurable:Module (NoMethodError)
I want to do the following in a commandline:
$ app something
> I did something!
$ app config
> You configured the app!
> I did something!
So here's the code:
# app.rb
require 'thor'
require_relative './cli'
class App < Thor
include Configurable
# def initialize ...
desc "something", "The Cli app does something"
def something
puts "I did something!"
end
end
# cli.rb
module Configurable
desc 'config', "You can configure the app"
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
end
As the above points out, when I comment out the desc 'config' .. line, it builds and runs, although Thor doesn't add the config command.
Thanks for your help!
UPDATE
I downloaded Thor's repo, and added traces when it encountered a desc command. So I tried calling Thor.desc instead, and I could see that it was loaded in Thor's system, but still didn't appear in commands list. So I played around and ended up with the following:
module Configurable
Thor.desc 'config', 'You can configure the app'
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
def self.included(klass)
puts "The module was included"
klass.desc "another", "another one"
end
def another
puts "Another!"
end
end
This way, I tested if calling desc before or after made a difference, but it didn't.
At this point, I would say it's Thor's limitations, and I can't achieve what I want with Thor and mixins.
desc is a method of Thor's singleton class, but Configurable isn't an instance of Thor's singleton class. (Obviously.) That's why you can't call desc without a receiver, you will have to call it explicitly:
(Note: I don't have Thor, therefore, I cannot test this. It may or may not work.)
module Configurable
Thor.desc 'config', 'You can configure the app'
def config
puts "You configured the app!"
# You can even call App 'something' method
something
end
end

Kill all threads on terminate

I'm trying to create an app in ruby which can be started from command line and it does two things: runs a continous job (loop with sleep which runs some action [remote feed parsing]) with one thread and sinatra in a second thread. My code (simplified) looks like that:
require 'sinatra'
class MyApp < Sinatra::Base
get '/' do
"Hello!"
end
end
threads = []
threads << Thread.new do
loop do
# do something heavy
sleep 10
end
end
threads << Thread.new do
MyApp.run!
end
threads.each { |t| t.join }
The above code actually does it's job very well - the sinatra app is started an available under 4567 port and the do something heavy task is beeing fired each 10 seconds. However, i'm not able to kill that script.
I'm running it with ruby app.rb but killing it with ctrl + c is not working. It kills just the sinatra thread but the second one is still running and, to stop the script, i need to close the terminal window.
I was trying to kill all the threads on SIGNINT but it's also not working as expected
trap "SIGINT" do
puts "Exiting"
threads.each { |t| Thread.kill t }
exit 130
end
Can you help me with this? Thanks in advance.
To trap ctrl-c, change "SIGINT" to "INT".
trap("INT") {
puts "trapping"
threads.each{|t|
puts "killing"
Thread.kill t
}
}
To configure Sinatra to skip catching traps:
class MyApp < Sinatra::Base
configure do
set :traps, false
end
...
Reference: Ruby Signal module
To list the available Ruby signals: Signal.list.keys
Reference: Sinatra Intro
(When I run your code and trap INT, I do get a Sinatra socket warning "Already in use". I presume that's fine for your purposes, or you can solve that by doing a Sinatra graceful shutdown. See Sinatra - terminate server from request)
Late to the party, but Trap has one big disadvantage - it gets overriden by the webserver. For example, Puma sets several traps which basically makes your one never to be called.
The best workaround is to use at_exit which can be defined multiple times and Ruby makes sure all blocks are called. I haven't tested this if it would work for your case tho.

implementing logger in ruby script

This is a ruby script which i am using to log my status.
require 'logger'
log = Logger.new( 'log.txt', 'daily' )
log.debug "Once the log becomes at least one"
log.debug "day old, it will be renamed and a"
log.debug "new log.txt file will be created."
Now i want to make a new ruby file in which i want to include logger it can be like this
module Logging
def logger
Logging.logger
end
def self.logger
#logger ||= Logger.new(STDOUT)
end
end
But i am not able to understand this so can anyone explain it.
my requirement is like there are lots of ruby script file i want to put a logger in module and include that in every file than write log in log file it can be warning it can be a info or anything else.
A better alternative would be:
module Logging
def logger
#logger ||= Logger.new(STDOUT)
end
end
And use it like this
class MyLoggingClient
include Logging
#Now you have access to the method `logger` and the instance variable `#logger`.
end
What I can gather from your question is the code works... you're just confused on what it does... if that's correct then to explain, when you inculde Logging in any of your classes the from anywhere in the classes methods call logger.log("This is a log message") it will log that message to the console that started the scripts.
Does that answer your question?

Capistrano's run_locally doesn't print to console?

Assume I have a custom task in my recipe as such:
task :custom_task1 do
run_locally "cap -S config=blah another_custom_task
end
and
task :another_custom_task do
puts "hi"
end
Then, "hi" won't be printed.
How to fix or overcome the situation? It is not allowing me to use command line whatsoever.
Edit:
Why can't I use logger?
Capistrano, by default talks too much - so I have a setting that sets its logger to shout only important errors. So can't use logger.info or something as such.
Try to use Logger:
logger.info "hi"

How do you test code that forks using rspec

I have the following code
def start_sunspot_server
unless #server
pid = fork do
STDERR.reopen("/dev/null")
STDOUT.reopen("/dev/null")
server.run
end
at_exit { Process.kill("TERM", pid) }
wait_until_solr_starts
end
end
How would I effectively go about testing it using rspec?
I thought something along
Kernel.should_receive(:fork)
STDERR.should_receive(:reopen).with("/dev/null")
STDOUT.should_receive(:reopen).with("/dev/null")
server.should_receive(:run)
etc
I'm confused by the #server instance variable and server method in your example, but here is an example that should help you get where you're trying to go:
class Runner
def run
fork do
STDERR.reopen("/dev/null")
end
end
end
describe "runner" do
it "#run reopens STDERR at /dev/null" do
runner = Runner.new
runner.should_receive(:fork) do |&block|
STDERR.should_receive(:reopen).with("/dev/null")
block.call
end
runner.run
end
end
The key is that the fork message is sent to the Runner object itself, even though its implementation is in the Kernel module.
HTH,
David
David's solution didn't work for us. Maybe it's because we're not using RSpec 2?
Here's what did work.
def run
fork do
blah
end
end
describe '#run' do
it 'should create a fork which calls #blah' do
subject.should_receive(:fork).and_yield do |block_context|
block_context.should_receive(:blah)
end
subject.run_job
end
end
I'm not sure how this would apply when calling a constant, such as STDERR, but this was the only way we were able to accomplish fork testing.

Resources