Ruby Logger rotation on CentOs - ruby

I´m doing some tests with default ruby Logger
and I´m getting this error on file rotation
log rotation inter-process lock failed. Text file busy #
rb_file_s_rename - (file.log, file.log.0)
log writing failed. closed stream
log shifting failed. closed stream
My environment.
CentOS 7.2.1511
Ruby: 2.0.0, 2.1.0, 2.3.0, 2.3.1
Note:
This error only occurs on CentOS with ruby versions after 2.0.0. With ruby 2.0.0 works fine!
I made some tests using Ubuntu with all ruby versions after 1.9 and
this error not occurs.
Here my test code
require 'logger'
begin
puts "Starting test"
# rotate when file size equals 20kb keeping 3 old logs
log = Logger.new("file.log", 3, 20000)
while true
puts "Logging..."
log.info "info"
log.error "error"
log.warn "warn"
log.debug "debug"
sleep(1)
end
rescue Interrupt => _
puts "Exiting..."
end
Thanks for help

Related

Avoid display of backtrace when running Sinatra on an already taken port

What is the proper way to prevent Sinatra from displaying the full backtrace, when it fails to properly run the server (for example, due to the port being already in use)?
This is a sample sinatra app:
# test.rb
require 'sinatra'
require 'bundler/inline'
gemfile do
gem 'sinatra'
gem 'puma'
end
set :bind, "0.0.0.0"
set :port, 3000
get '/' do
"hello"
end
Then, running it with ruby test.rb once, to occupy the port.
Then, running it again in another terminal window, and this full error backtrace is shown:
$ ruby test.rb
== Sinatra (v2.0.4) has taken the stage on 3000 for development with backup from Puma
Puma starting in single mode...
* Version 3.12.0 (ruby 2.5.0-p0), codename: Llamas in Pajamas
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000
== Someone is already performing on port 3000!
Traceback (most recent call last):
5: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/main.rb:26:in `block in <module:Sinatra>'
4: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1464:in `run!'
3: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1464:in `ensure in run!'
2: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1439:in `quit!'
1: from /store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/launcher.rb:147:in `stop'
/store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/single.rb:27:in `stop': undefined method `stop' for nil:NilClass (NoMethodError)
Traceback (most recent call last):
3: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1545:in `block in setup_traps'
2: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1439:in `quit!'
1: from /store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/launcher.rb:147:in `stop'
/store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/single.rb:27:in `stop': undefined method `stop' for nil:NilClass (NoMethodError)
Since I am using it as an embedded server, I would like the output to simply and with the friendly error that Sinatra is already showing:
== Someone is already performing on port 3000!
and avoid showing the backtrace.
Ruby by default outputs error messages to the STDOUT. But if you're on *nix system you can do this:
ruby test.rb > /dev/null 2>&1
For windows you can probably do
ruby test.rb > NULL
windows powershell
ruby test.rb > $null
but for windows also see Is there a /dev/null on Windows?
But if you want programmatically suppress output when server is running this should work on *nix but not sure on windows
# test.rb
require 'sinatra'
require 'bundler/inline'
gemfile do
gem 'sinatra'
gem 'puma'
end
set :bind, "0.0.0.0"
set :port, 3000
get '/' do
"hello"
end
unless `ps aux | grep sinatra`.match('tcp://0.0.0.0:3000')
STDOUT.reopen('/dev/null', 'w')
STDERR.reopen('/dev/null', 'w')
end
See suppresing output to console with ruby
You can test to see if the port is in use by attempting to listen on the port before allowing Sinatra and Puma to take over. This isn't 100% effective because there's a race condition where you may open and close the port, but before Sinatra/Puma finish initializing some other process comes along and listens on the same port, but it should work for your use-case (which appears to be a cosmetic hack only).
Insert this code anywhere in test.rb:
require 'socket'
include Socket::Constants
begin
# Open and close the port
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.pack_sockaddr_in(3000, '0.0.0.0')
socket.bind(sockaddr)
socket.listen(1)
socket.close
rescue Errno::EADDRINUSE => error
# Traps the same error that is trapped by Sinatra and exits if raised
puts error.message
exit
end
Start the first one with ruby test.rb:
== Sinatra (v2.0.4) has taken the stage on 3000 for development with backup from Puma
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.0-p-1), codename: Llamas in Pajamas
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Start the second one with ruby test.rb:
Address already in use - bind(2) for 0.0.0.0:3000
You can flesh out what you want printed to the console inside the rescue block.
This appears to be caused by an issue with Puma, that is fixed by this PR.

Thread deadlock on simple operations in pry

[Note: I "fixed" this problem by creating and using a new gemset. I'm still curious why the problem occurred but it is no longer blocking me.]
[I am aware that there is a similar issue at Deadlock in Ruby join(), but I have tried the timeout parameter suggested there and it does not help. I suspect there is a pry-specific problem not covered there.]
I am getting the error below when running the code below, but only when executed within a pry session. This code has not been changed and has been working fine for quite a while, and I have no idea why it's an issue just now. I am using pry version 0.11.3 on Ruby 2.5.1. Also, this code works fine when pasted into pry; it's not working in my wifi-wand application that launches pry in the context of one of its objects (gem install wifi-wand to install, https://github.com/keithrbennett/wifiwand is the project page).
domains = %w(google.com baidu.com)
puts "Calling dig on domains #{domains}..." if #verbose_mode
threads = domains.map do |domain|
Thread.new do
output = `dig +short #{domain}`
output.length > 0
end
end
threads.each(&:join)
[1] pry(#<WifiWand::CommandLineInterface>)> ci
Calling dig on domains ["google.com", "baidu.com"]...
fatal: No live threads left. Deadlock?
3 threads, 3 sleeps current:0x00007fbd13d0c5a0 main thread:0x00007fbd13d0c5a0
* #<Thread:0x00007fbd14069c20 sleep_forever>
rb_thread_t:0x00007fbd13d0c5a0 native:0x00007fff89c2b380 int:0
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `join'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `each'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:89:in `block in connected_to_internet?'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/models/base_model.rb:126:in `connected_to_internet?'
/Users/kbennett/work/wifi-wand/lib/wifi-wand/command_line_interface.rb:264:in `cmd_ci'
Strangely, the problem was fixed by uninstalling and reinstalling the awesome_print gem. I have no idea why.

IO::EAGAINWaitReadable: Resource temporarily unavailable - read would block

I get the following error when I try to use the method "read_nonblock" from the "socket" library
IO::EAGAINWaitReadable: Resource temporarily unavailable - read would block
But when I try it through the IRB on the terminal it works fine
How can I make it read the buffer?
I get the following error when I try to use the method "read_nonblock" from the "socket" library
It is expected behaviour when the data isn't ready in the buffer. Since the exception, IO::EAGAINWaitReadable is originated from ruby version 2.1.0, in older version you must trap IO::WaitReadable with additional port selection and retry. So do as it was adviced in the ruby documentation:
begin
result = io.read_nonblock(maxlen)
rescue IO::WaitReadable
IO.select([io])
retry
end
For newer version os ruby you should trap IO::EAGAINWaitReadable also, but just with retrial reading for a timeout or infinitely. I haven't found out the example in the docs, but remember that it was without port selection:
begin
result = io.read_nonblock(maxlen)
rescue IO::EAGAINWaitReadable
retry
end
However some my investigations lead to that it is also better to do port selection on IO::EAGAINWaitReadable, so you'll can get:
begin
result = io.read_nonblock(maxlen)
rescue IO::WaitReadable, IO::EAGAINWaitReadable
IO.select([io])
retry
end
To support the code with both versions of exception, just declare the definition of IO::EAGAINWaitReadable in lib/ core under if clause:
if ! ::IO.const_defined?(:EAGAINWaitReadable)
class ::IO::EAGAINWaitReadable; end
end

retry in Ruby can not be performed

for i in 1..5
retry if i > 2
puts "Value of local variable is #{i}"
end
When I ran the code above, I got an error message saying Invalid retry
The version of Ruby I was using is 1.9.3. Would anyone know what went wrong with the code?
From Ruby 1.9 onwards retry needs to be in a rescue clause and will only work when in a rescue clause

Ruby Net-SFTP Unresponsive

I'm trying to upload a file to a SFTP site using Net::SFTP.
The problem is the Ruby process never returns. It's frozen, stuck, never-ending... I have to Ctrl-C to make it stop.
I can connect to the ftp server in the command line using sftp.
I've tried this code on Linux (Ubuntu) and Snow Leopard and it does the same thing.
Installed the latest version of Net::SSH and Net::SFTP.
From gem list net:
net-sftp (2.0.5)
net-ssh (2.1.4)
Different combinations of hash arguments (see code below)
Tried to call Net::SFTP.start instead of creating a SSH session first.
Server responds with "SFTP protocol version 3" when I login using a command line tool and ask for the version.
I'm running Ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10.7.0]
Debug output from :verbose (last couple of lines):
D, [2011-07-29T17:30:52.692192 #19399] DEBUG -- tcpsocket[80c06478]: read 36 bytes
D, [2011-07-29T17:30:52.692609 #19399] DEBUG -- tcpsocket[80c06478]: received packet nr 7 type 99 len 12
I, [2011-07-29T17:30:52.692751 #19399] INFO -- net.ssh.connection.session[80bd5da0]: channel_success: 0
D, [2011-07-29T17:30:52.692817 #19399] DEBUG -- net.sftp.session[80bd5c24]: sftp subsystem successfully started
D, [2011-07-29T17:30:52.693625 #19399] DEBUG -- tcpsocket[80c06478]: queueing packet nr 8 type 94 len 28
D, [2011-07-29T17:30:52.693834 #19399] DEBUG -- tcpsocket[80c06478]: sent 52 bytes
Sample code:
require 'rubygems'
require 'net/sftp'
FTP = "someftpsite"
FTP_USER_NAME = "user"
FTP_PASSWORD = "password"
hash = {:password => FTP_PASSWORD, :verbose => :debug, :keys=>[""],:auth_methods => ["password"], :timeout => 5, :port=>22}
begin
Net::SSH.start(FTP,FTP_USER_NAME, hash) do |test|
test.sftp.upload!("localfile","remotefile")
end
rescue Exception => err
puts "error:#{err.inspect}"
end
Edit: 8/22/2011
This seems to be related to the interactiveness of the SFTP server. I solved this by creating a shell script using expect and shelling out from Ruby to run the file. The shell script is created at run time. This seems really hackish, but it's the only way I've been able to make it work using Ruby. If anyone else has a suggestion, I would love to find a better way to do this.
You could use public/private key authentication instead. http://net-ssh.rubyforge.org/ssh/v1/chapter-2.html#s2

Resources