লগারে টিয়ের কার্যকারিতার মতো কিছু করা।
লগারে টিয়ের কার্যকারিতার মতো কিছু করা।
tee --append test.logওভাররাইটগুলি রোধ করতে @ এমজেওয়্যাটস ব্যবহার করুন ।
উত্তর:
আপনি সিউডো IOক্লাস লিখতে পারেন যা একাধিক IOবস্তুতে লিখবে । কিছুটা এইরকম:
class MultiIO
def initialize(*targets)
@targets = targets
end
def write(*args)
@targets.each {|t| t.write(*args)}
end
def close
@targets.each(&:close)
end
end
তারপরে আপনার লগ ফাইল হিসাবে সেট করুন:
log_file = File.open("log/debug.log", "a")
Logger.new MultiIO.new(STDOUT, log_file)
প্রতিবার আপনার অবজেক্টে Loggerকল করলে এটি এবং আপনার লগ ফাইল উভয়কেই লিখবে ।putsMultiIOSTDOUT
সম্পাদনা: আমি এগিয়ে গিয়েছিলাম এবং বাকী ইন্টারফেসটি বের করে ফেললাম। একটি লগ ডিভাইস অবশ্যই জবাব দেবে writeএবং close(না puts)। যতক্ষণ MultiIOনা তাদের প্রতিক্রিয়া জানায় এবং প্রকৃত আইও অবজেক্টগুলিতে তাদের প্রক্স করবেন ততক্ষণ এটি কাজ করা উচিত।
def initialize(log = nil, opt = {}) @dev = @filename = @shift_age = @shift_size = nil @mutex = LogDeviceMutex.new if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @dev = open_logfile(log) @dev.sync = true @filename = log @shift_age = opt[:shift_age] || 7 @shift_size = opt[:shift_size] || 1048576 end end
@targets.each(&:close)হ্রাস করা হয়েছে।
@ ডেভিডের সমাধান খুব ভাল। আমি তার কোডের ভিত্তিতে একাধিক টার্গেটের জন্য জেনেরিক প্রতিনিধি শ্রেণি তৈরি করেছি।
require 'logger'
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def self.delegate(*methods)
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
self
end
class <<self
alias to new
end
end
log_file = File.open("debug.log", "a")
log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
যদি আপনি এই ব্লগ পোস্টটি দেখায় যে 3 বা 4 রেলের মধ্যে রয়েছেন তবে 4 রিলগুলিতে এই কার্যকারিতাটি অন্তর্নিহিত রয়েছে । সুতরাং আপনি এটি করতে পারেন:
# config/environment/production.rb
file_logger = Logger.new(Rails.root.join("log/alternative-output.log"))
config.logger.extend(ActiveSupport::Logger.broadcast(file_logger))
বা আপনি যদি রেল 3 এ থাকেন তবে আপনি এটি ব্যাকপোর্ট করতে পারেন:
# config/initializers/alternative_output_log.rb
# backported from rails4
module ActiveSupport
class Logger < ::Logger
# Broadcasts logs to multiple loggers. Returns a module to be
# `extended`'ed into other logger instances.
def self.broadcast(logger)
Module.new do
define_method(:add) do |*args, &block|
logger.add(*args, &block)
super(*args, &block)
end
define_method(:<<) do |x|
logger << x
super(x)
end
define_method(:close) do
logger.close
super()
end
define_method(:progname=) do |name|
logger.progname = name
super(name)
end
define_method(:formatter=) do |formatter|
logger.formatter = formatter
super(formatter)
end
define_method(:level=) do |level|
logger.level = level
super(level)
end
end
end
end
end
file_logger = Logger.new(Rails.root.join("log/alternative-output.log"))
Rails.logger.extend(ActiveSupport::Logger.broadcast(file_logger))
extendকোনও ActiveSupport::Loggerউদাহরণ দেখতে পারেন ।
config.logger.extend()আমার পরিবেশের কনফিগারেশনটির অভ্যন্তরটি ব্যবহার করে আমার কিছুটা অদ্ভুততা ছিল । পরিবর্তে, আমি সেট config.loggerকরতে STDOUTআমার পরিবেশে, তারপর বিভিন্ন initializers মধ্যে এটির বাড়ানো।
যারা এটি সহজ পছন্দ করেন তাদের জন্য:
log = Logger.new("| tee test.log") # note the pipe ( '|' )
log.info "hi" # will log to both STDOUT and test.log
অথবা লগার বিন্যাসে বার্তাটি মুদ্রণ করুন:
log = Logger.new("test.log")
log.formatter = proc do |severity, datetime, progname, msg|
puts msg
msg
end
log.info "hi" # will log to both STDOUT and test.log
আমি আসলে এই কৌশলটি লগ ফাইল, একটি ক্লাউড লগার পরিষেবা (লজেন্টারি) এবং এটি যদি পরিবেশের পরিবেশে মুদ্রণ করতে ব্যবহার করি তবে এসটিওআউট-এ মুদ্রণ করুন।
"| tee test.log"পুরানো আউটপুটগুলি ওভাররাইট করে দেবে, "| tee -a test.log"পরিবর্তে হতে পারে
যদিও আমি অন্যান্য পরামর্শগুলি বেশ পছন্দ করি, আমি দেখতে পেয়েছিলাম যে আমার এই একই সমস্যা রয়েছে তবে এসটিডিআরআর এবং ফাইলের জন্য বিভিন্ন লগিং স্তর রাখার সক্ষমতা চেয়েছিলাম।
আমি একটি রাউটিং কৌশলটি শেষ করেছি যা আইও স্তরের চেয়ে লগার স্তরে মাল্টিপ্লেক্সগুলি তৈরি করে, যাতে প্রতিটি লগার স্বতন্ত্র লগ-স্তরে কাজ করতে পারে:
class MultiLogger
def initialize(*targets)
@targets = targets
end
%w(log debug info warn error fatal unknown).each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
end
stderr_log = Logger.new(STDERR)
file_log = Logger.new(File.open('logger.log', 'a'))
stderr_log.level = Logger::INFO
file_log.level = Logger::DEBUG
log = MultiLogger.new(stderr_log, file_log)
MultiLogger@Dz বর্ণনা করার মতো একটি হ'ল একটি দুর্দান্ত ফিট। ভাগ করে নেওয়ার জন্য ধন্যবাদ!
আপনি সরাসরি লগারে একাধিক ডিভাইস লগিং কার্যকারিতা যুক্ত করতে পারেন:
require 'logger'
class Logger
# Creates or opens a secondary log file.
def attach(name)
@logdev.attach(name)
end
# Closes a secondary log file.
def detach(name)
@logdev.detach(name)
end
class LogDevice # :nodoc:
attr_reader :devs
def attach(log)
@devs ||= {}
@devs[log] = open_logfile(log)
end
def detach(log)
@devs ||= {}
@devs[log].close
@devs.delete(log)
end
alias_method :old_write, :write
def write(message)
old_write(message)
@devs ||= {}
@devs.each do |log, dev|
dev.write(message)
end
end
end
end
এই ক্ষেত্রে:
logger = Logger.new(STDOUT)
logger.warn('This message goes to stdout')
logger.attach('logfile.txt')
logger.warn('This message goes both to stdout and logfile.txt')
logger.detach('logfile.txt')
logger.warn('This message goes just to stdout')
@ জোনাস054 এর উত্তরে অনুপ্রাণিত হয়ে এখানে আরও একটি বাস্তবায়ন ।
এটি অনুরূপ একটি প্যাটার্ন ব্যবহার করে Delegator। এইভাবে আপনাকে যে সমস্ত পদ্ধতিটি অর্পণ করতে চান তা আপনাকে তালিকাভুক্ত করতে হবে না, কারণ এটি লক্ষ্যবস্তুগুলির যে কোনও একটিতে সংজ্ঞায়িত সমস্ত পদ্ধতি নির্ধারণ করবে:
class Tee < DelegateToAllClass(IO)
end
$stdout = Tee.new(STDOUT, File.open("#{__FILE__}.log", "a"))
আপনার এটি লগারের সাথেও ব্যবহার করতে সক্ষম হওয়া উচিত।
প্রতিনিধি_ টো_ল.আরবি এখানে থেকে পাওয়া যায়: https://gist.github.com/TylerRick/4990898
দ্রুত এবং নোংরা (রেফ: https://coderwall.com/p/y_b3ra/log-to-stdout-and-a-file-at-the-same- সময় )
require 'logger'
ll=Logger.new('| tee script.log')
ll.info('test')
উপরে jonas054 এর উত্তর দুর্দান্ত, তবে এটি MultiDelegatorপ্রতিটি নতুন প্রতিনিধি সহ শ্রেণিটিকে দূষিত করে। আপনি যদি ব্যবহারMultiDelegator বেশ কয়েকবার করেন তবে এটি ক্লাসে পদ্ধতিগুলি যুক্ত করতে থাকবে যা অবাঞ্ছিত। (উদাহরণস্বরূপ বেলো দেখুন)
এখানে একই বাস্তবায়ন, তবে বেনামে ক্লাস ব্যবহার করা যাতে পদ্ধতিগুলি প্রতিনিধি শ্রেণিকে কলুষিত না করে।
class BetterMultiDelegator
def self.delegate(*methods)
Class.new do
def initialize(*targets)
@targets = targets
end
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
class <<self
alias to new
end
end # new class
end # delegate
end
পরিবর্তিত বাস্তবায়নের বিপরীতে মূল প্রয়োগের সাথে পদ্ধতি দূষণের একটি উদাহরণ এখানে রয়েছে:
tee = MultiDelegator.delegate(:write).to(STDOUT)
tee.respond_to? :write
# => true
tee.respond_to? :size
# => false
উপরে সব ভাল। teeএকটি writeপদ্ধতি আছে তবে sizeপ্রত্যাশার মতো কোনও পদ্ধতি নেই । এখন, বিবেচনা করুন যখন আমরা অন্য প্রতিনিধি তৈরি করি:
tee2 = MultiDelegator.delegate(:size).to("bar")
tee2.respond_to? :size
# => true
tee2.respond_to? :write
# => true !!!!! Bad
tee.respond_to? :size
# => true !!!!! Bad
ওহ না, প্রত্যাশার মতো tee2প্রতিক্রিয়া জানায় size, তবে writeপ্রথম প্রতিনিধি হওয়ার কারণে এটিও সাড়া দেয় । এমনকি teeএখন sizeপদ্ধতি দূষণের কারণে সাড়া দেয় ।
এটি বেনাম শ্রেণীর সমাধানের সাথে বিপরীতে করুন, সবকিছু প্রত্যাশার মতো:
see = BetterMultiDelegator.delegate(:write).to(STDOUT)
see.respond_to? :write
# => true
see.respond_to? :size
# => false
see2 = BetterMultiDelegator.delegate(:size).to("bar")
see2.respond_to? :size
# => true
see2.respond_to? :write
# => false
see.respond_to? :size
# => false
আপনি কি স্ট্যান্ডার্ড লগার সীমাবদ্ধ?
যদি না আপনি ব্যবহার করতে পারেন log4r :
require 'log4r'
LOGGER = Log4r::Logger.new('mylog')
LOGGER.outputters << Log4r::StdoutOutputter.new('stdout')
LOGGER.outputters << Log4r::FileOutputter.new('file', :filename => 'test.log') #attach to existing log-file
LOGGER.info('aa') #Writs on STDOUT and sends to file
একটি সুবিধা: আপনি স্টডআউট এবং ফাইলের জন্য বিভিন্ন লগ-স্তরগুলিও সংজ্ঞায়িত করতে পারেন।
অন্যান্য লোকেরা ইতিমধ্যে অন্বেষণ করে থাকা "উপ-উপাদানগুলিতে সমস্ত পদ্ধতি হস্তান্তর" করার একই ধারণায় আমি গিয়েছিলাম, তবে তাদের প্রতিটিটির জন্য পদ্ধতির শেষ কলটির রিটার্ন মান ফিরে আসছি। যদি আমি না করতাম তবে এটি ভেঙেছিল logger-colorsযা একটি প্রত্যাশা করেছিল Integerএবং মানচিত্রটি ফিরে আসছিল Array।
class MultiIO
def self.delegate_all
IO.methods.each do |m|
define_method(m) do |*args|
ret = nil
@targets.each { |t| ret = t.send(m, *args) }
ret
end
end
end
def initialize(*targets)
@targets = targets
MultiIO.delegate_all
end
end
এটি সমস্ত লক্ষ্যবস্তুতে প্রতিটি পদ্ধতি পুনরুদ্ধার করবে এবং কেবলমাত্র শেষ কলের রিটার্ন মানটি ফিরিয়ে দেবে।
এছাড়াও, আপনি যদি রঙ চান, STDOUT বা STDERR অবশ্যই শেষ রাখতে হবে, কারণ এটি কেবলমাত্র দুটি রঙের আউটপুট হওয়ার কথা। তবে, এটি আপনার ফাইলে রঙও আউটপুট করবে।
logger = Logger.new MultiIO.new(File.open("log/test.log", 'w'), STDOUT)
logger.error "Roses are red"
logger.unknown "Violets are blue"
আমি একটি সামান্য রুবিগেম লিখেছি যা আপনাকে এই কয়েকটি কাজ করতে অনুমতি দেয়:
# Pipe calls to an instance of Ruby's logger class to $stdout
require 'teerb'
log_file = File.open("debug.log", "a")
logger = Logger.new(TeeRb::IODelegate.new(log_file, STDOUT))
logger.warn "warn"
$stderr.puts "stderr hello"
puts "stdout hello"
আরও একটি উপায়। আপনি যদি ট্যাগযুক্ত লগিং ব্যবহার করছেন এবং অন্য লগফাইলে পাশাপাশি ট্যাগগুলির প্রয়োজন হয়, আপনি এটি এইভাবে করতে পারেন
# backported from rails4
# config/initializers/active_support_logger.rb
module ActiveSupport
class Logger < ::Logger
# Broadcasts logs to multiple loggers. Returns a module to be
# `extended`'ed into other logger instances.
def self.broadcast(logger)
Module.new do
define_method(:add) do |*args, &block|
logger.add(*args, &block)
super(*args, &block)
end
define_method(:<<) do |x|
logger << x
super(x)
end
define_method(:close) do
logger.close
super()
end
define_method(:progname=) do |name|
logger.progname = name
super(name)
end
define_method(:formatter=) do |formatter|
logger.formatter = formatter
super(formatter)
end
define_method(:level=) do |level|
logger.level = level
super(level)
end
end # Module.new
end # broadcast
def initialize(*args)
super
@formatter = SimpleFormatter.new
end
# Simple formatter which only displays the message.
class SimpleFormatter < ::Logger::Formatter
# This method is invoked when a log event occurs
def call(severity, time, progname, msg)
element = caller[4] ? caller[4].split("/").last : "UNDEFINED"
"#{Thread.current[:activesupport_tagged_logging_tags]||nil } # {time.to_s(:db)} #{severity} #{element} -- #{String === msg ? msg : msg.inspect}\n"
end
end
end # class Logger
end # module ActiveSupport
custom_logger = ActiveSupport::Logger.new(Rails.root.join("log/alternative_#{Rails.env}.log"))
Rails.logger.extend(ActiveSupport::Logger.broadcast(custom_logger))
এর পরে আপনি বিকল্প লগারে uuid ট্যাগ পাবেন
["fbfea87d1d8cc101a4ff9d12461ae810"] 2015-03-12 16:54:04 INFO logger.rb:28:in `call_app' --
["fbfea87d1d8cc101a4ff9d12461ae810"] 2015-03-12 16:54:04 INFO logger.rb:31:in `call_app' -- Started POST "/psp/entrypoint" for 192.168.56.1 at 2015-03-12 16:54:04 +0700
আশা করি যে কাউকে সাহায্য করবে
ActiveSupport::Loggerএই সঙ্গে বাক্সের বাইরে কাজ করে - আপনি শুধু ব্যবহার করতে হবে Rails.logger.extendসঙ্গে ActiveSupport::Logger.broadcast(...)।
আরও একটি বিকল্প ;-)
require 'logger'
class MultiDelegator
def initialize(*targets)
@targets = targets
end
def method_missing(method_sym, *arguments, &block)
@targets.each do |target|
target.send(method_sym, *arguments, &block) if target.respond_to?(method_sym)
end
end
end
log = MultiDelegator.new(Logger.new(STDOUT), Logger.new(File.open("debug.log", "a")))
log.info('Hello ...')
আমি মাল্টিআইও পদ্ধতির পছন্দ করি । এটি রুবি লগারের সাথে ভাল কাজ করে । আপনি যদি খাঁটি আইও ব্যবহার করেন তবে এটি কাজ করা বন্ধ করে দেয় কারণ এতে কিছু পদ্ধতির অভাব রয়েছে যা IO অবজেক্টগুলির প্রত্যাশিত। পাইপগুলি এখানে আগে উল্লেখ করা হয়েছিল: আমি স্টাবআউটের পাশাপাশি ফাইলের মধ্যে রুবি লগার লগ আউটপুট কীভাবে রাখতে পারি? । এখানে আমার পক্ষে সবচেয়ে ভাল কাজ করে।
def watch(cmd)
output = StringIO.new
IO.popen(cmd) do |fd|
until fd.eof?
bit = fd.getc
output << bit
$stdout.putc bit
end
end
output.rewind
[output.read, $?.success?]
ensure
output.close
end
result, success = watch('./my/shell_command as a String')
দ্রষ্টব্য আমি জানি এটি সরাসরি প্রশ্নের উত্তর দেয় না তবে এটি দৃ strongly়ভাবে সম্পর্কিত। যখনই আমি একাধিক আইওগুলিতে আউটপুট অনুসন্ধান করেছি আমি এই থ্রেড জুড়ে এসেছি o সুতরাং, আমি আশা করি আপনিও এটি দরকারী খুঁজে পেয়েছেন।
এটি @ রাডোর সমাধানটির সরলীকরণ।
def delegator(*methods)
Class.new do
def initialize(*targets)
@targets = targets
end
methods.each do |m|
define_method(m) do |*args|
@targets.map { |t| t.send(m, *args) }
end
end
class << self
alias for new
end
end # new class
end # delegate
বাইরের শ্রেণীর মোড়ক ছাড়াই এটির মতো তার সমস্ত সুবিধা রয়েছে। পৃথক রুবি ফাইল রাখতে এটি একটি দরকারী ইউটিলিটি।
এটির মতো প্রতিনিধি উদাহরণ উত্পন্ন করতে এটি ওয়ান-লাইনার হিসাবে ব্যবহার করুন:
IO_delegator_instance = delegator(:write, :read).for(STDOUT, STDERR)
IO_delegator_instance.write("blah")
অথবা এটি কারখানার মতো ব্যবহার করুন:
logger_delegator_class = delegator(:log, :warn, :error)
secret_delegator = logger_delegator_class(main_logger, secret_logger)
secret_delegator.warn("secret")
general_delegator = logger_delegator_class(main_logger, debug_logger, other_logger)
general_delegator.log("message")
যদি আপনি ব্যবহারে ঠিক থাকেন ActiveSupportতবে আমি চেক আউট করার জন্য অত্যন্ত সুপারিশ করব ActiveSupport::Logger.broadcastযা কোনও লগারে অতিরিক্ত লগ গন্তব্য যুক্ত করার জন্য একটি দুর্দান্ত এবং খুব সংক্ষিপ্ত উপায়।
আসলে, আপনি যদি রেল 4+ ব্যবহার করেন ( এই প্রতিশ্রুতি হিসাবে ), আপনার পছন্দসই আচরণ পেতে কোনও কিছুই করার দরকার নেই - কমপক্ষে যদি আপনি এটি ব্যবহার করেন rails console। আপনি যখনই এটি ব্যবহার করেন rails console, তখনই স্বয়ংক্রিয়ভাবে এরগুলি প্রসারিত হয় Rails.loggerযা এটি উভয়কেই তার স্বাভাবিক ফাইল গন্তব্যে ( log/production.logউদাহরণস্বরূপ) এবং আউটপুট দেয় STDERR:
console do |app|
…
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDERR, STDOUT)
console = ActiveSupport::Logger.new(STDERR)
Rails.logger.extend ActiveSupport::Logger.broadcast console
end
ActiveRecord::Base.verbose_query_logs = false
end
কিছু অজানা এবং দুর্ভাগ্যজনক কারণে, এই পদ্ধতিটি অননুমোদিত তবে এটি কীভাবে কাজ করে তা জানতে বা উদাহরণগুলি দেখতে আপনি উত্স কোড বা ব্লগ পোস্টগুলি উল্লেখ করতে পারেন।
https://www.joshmcarthur.com/til/2018/08/16/logging-to-m Multipleple-destferences- using- activesupport-4.html এর আরও একটি উদাহরণ রয়েছে:
require "active_support/logger"
console_logger = ActiveSupport::Logger.new(STDOUT)
file_logger = ActiveSupport::Logger.new("my_log.log")
combined_logger = console_logger.extend(ActiveSupport::Logger.broadcast(file_logger))
combined_logger.debug "Debug level"
…
আমারও সম্প্রতি এটির প্রয়োজন রয়েছে তাই আমি এমন একটি লাইব্রেরি প্রয়োগ করেছি যা এটি করে। আমি এই স্ট্যাক ওভারফ্লো প্রশ্নটি সন্ধান করেছি, সুতরাং যার প্রয়োজন তার জন্য আমি এটি এখানে রেখে দিচ্ছি: https://github.com/agis/m মাল্টি_ও ।
এখানে উল্লিখিত অন্যান্য সমাধানগুলির সাথে তুলনা করে IO, এটি নিজস্ব একটি বস্তু হতে চেষ্টা করে , তাই এটি অন্যান্য নিয়মিত আইও অবজেক্টগুলির জন্য ফাইল-ড্রপ-ইন প্রতিস্থাপন (ফাইল, সকেট ইত্যাদি) হিসাবে ব্যবহার করা যেতে পারে
এটি বলেছিল, আমি এখনও সমস্ত স্ট্যান্ডার্ড আইও পদ্ধতি বাস্তবায়ন করি নি, তবে সেগুলি আইও শব্দার্থবিজ্ঞানের অনুসরণ করে (উদাহরণস্বরূপ, #writeসমস্ত অন্তর্নিহিত আইও টার্গেটগুলিতে লিখিত বাইটের সংখ্যার যোগফল দেয়)।
আমি মনে করি আপনার STDOUT সমালোচিত রানটাইম তথ্য এবং উত্থাপিত ত্রুটিগুলির জন্য ব্যবহৃত হয়।
সুতরাং আমি ব্যবহার
$log = Logger.new('process.log', 'daily')
ডিবাগ এবং নিয়মিত লগিং লগ করতে, এবং তারপরে কয়েকটি লিখেছিলেন
puts "doing stuff..."
যেখানে আমার স্ট্রিপ্ট তথ্য দেখতে হবে যে আমার স্ক্রিপ্টগুলি আদৌ চলছে!
বাহ, মাত্র আমার 10 সেন্ট :-)
| teeফাইলটি যুক্ত করার আগে আমার পক্ষে কাজ হয়েছিল, তাইLogger.new("| tee test.log")। পাইপ নোট করুন। এটি কোডারওয়াল