স্টাবআউটের পাশাপাশি ফাইলের মধ্যে আমি রুবি লগার লগ আউটপুট কীভাবে রাখতে পারি?


95

লগারে টিয়ের কার্যকারিতার মতো কিছু করা।


4
| teeফাইলটি যুক্ত করার আগে আমার পক্ষে কাজ হয়েছিল, তাই Logger.new("| tee test.log")পাইপ নোট করুন। এটি কোডারওয়াল
মাইক ডব্লু

tee --append test.logওভাররাইটগুলি রোধ করতে @ এমজেওয়্যাটস ব্যবহার করুন ।
২৮ শে

উত্তর:


124

আপনি সিউডো 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
জেফচার্টার

4
রুবি ২.২-এ থাকা নোটটি @targets.each(&:close)হ্রাস করা হয়েছে।
এক্সিস

যতক্ষণ না বুঝতে পেরেছি আমি পর্যায়ক্রমে কল করতে হবে: লগ-ইন ফাইলটি লগ-ইন করতে আপডেট করার জন্য লগ_ফাইলে বন্ধ করুন (মূলত একটি "সংরক্ষণ")। STDOUT পছন্দ করেনি: এটির কাছে ডাকা হচ্ছে, মুল্টোআইও ধারণাটিকে পরাস্ত করার। এড়াতে একটি হ্যাক যুক্ত হয়েছে: ক্লাস ফাইল বাদে বন্ধ করুন, তবে আশা করি আমার আরও মার্জিত সমাধান পাওয়া উচিত।
কিম মিলার

48

@ ডেভিডের সমাধান খুব ভাল। আমি তার কোডের ভিত্তিতে একাধিক টার্গেটের জন্য জেনেরিক প্রতিনিধি শ্রেণি তৈরি করেছি।

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)

আপনি দয়া করে ব্যাখ্যা করতে পারেন, ডেভিডের প্রস্তাবিত সমতলের চেয়ে এটি কীভাবে ভাল বা এই পদ্ধতির বর্ধিত ইউটিলিটিগুলি কী
মণীশ সাপরিয়া

4
এটি উদ্বেগের বিচ্ছেদ। মাল্টিডেলিগেটর কেবল একাধিক লক্ষ্যগুলিতে কল অর্পণ করার বিষয়েই জানে। লগিং ডিভাইসটির একটি লেখার প্রয়োজন এবং এই ঘটনায় কলারটিতে একটি ঘনিষ্ঠ পদ্ধতি প্রয়োগ করা হয়। এটি লগিংয়ের চেয়ে অন্যান্য পরিস্থিতিতে মাল্টিডেলিগেটরকে ব্যবহারযোগ্য করে তোলে।
jonas054

সুন্দর সমাধান। আমি আমার রেক টাস্ক থেকে লগ ফাইলে আউটপুট টিপতে এটি ব্যবহার করার চেষ্টা করেছি। যদিও এটি পুটগুলির সাথে কাজ করার জন্য ("প্রাইভেট পদ্ধতি called পুটস" না পেয়ে $ stdout.puts কল করতে সক্ষম হতে), আমাকে আরও কয়েকটি পদ্ধতি যুক্ত করতে হয়েছিল: log_file = File.open ("tmp / rake.log "," a ") d stdout = MultiDelegator.delegate (: লিখুন,: বন্ধ,: পুটস,: মুদ্রণ)। টু (স্টাডিআউট, লগ_ফাইলে) উত্তরাধিকার সূত্রে প্রাপ্ত কোনও টি ক্লাস তৈরি করা সম্ভব হলে ভাল হত মাল্টিডেলিগেটর, যেমন আপনি স্টাডলিবের প্রতিনিধি শ্রেণীর সাথে করতে পারেন ...
টাইলার রিক

আমি ডেলিগেটর টোঅলকে ডেকে এটিকে ডেলিগেটরের মতো প্রয়োগের সাথে নিয়ে এসেছি। এইভাবে আপনাকে যে সমস্ত পদ্ধতিতে ডেলিগ্রেট করতে চান তা আপনাকে তালিকাভুক্ত করতে হবে না, যেহেতু এটি প্রতিনিধি শ্রেণিতে (আইও) সংজ্ঞায়িত সমস্ত পদ্ধতি নির্ধারণ করবে: ক্লাস টি <ডিলেগেটটোঅলক্লাস (আইও) শেষ $ স্টডআউট = টি.নেউ (এসটিডিআউট) , ফাইল.ওপেন ("# { ফাইল }। লগ", "ক")) আরও বিশদের জন্য gist.github.com/TylerRick/4990898 দেখুন ।
টাইলার রিক

4
আমি আপনার সমাধানটি সত্যিই পছন্দ করি তবে জেনেরিক প্রতিনিধি হিসাবে এটি ভাল নয় যা প্রতিটি প্রতিনিধি নতুন পদ্ধতির সাহায্যে সমস্ত ঘটনা দূষিত করে as আমি একটি উত্তর বেলো পোস্ট করেছি ( stackoverflow.com/a/36659911/123376 ) যা এই সমস্যার সমাধান করে। আমি সম্পাদনার পরিবর্তে একটি উত্তর পোস্ট করেছি যেহেতু আমি উদাহরণগুলি পোস্ট করার সাথে সাথে দুটি বাস্তবায়নের মধ্যে পার্থক্যটি দেখাও শিক্ষামূলক হতে পারে।
রাদো

35

যদি আপনি এই ব্লগ পোস্টটি দেখায় যে 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 মধ্যে এটির বাড়ানো।
ম্যাটসচ

14

যারা এটি সহজ পছন্দ করেন তাদের জন্য:

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

আমি আসলে এই কৌশলটি লগ ফাইল, একটি ক্লাউড লগার পরিষেবা (লজেন্টারি) এবং এটি যদি পরিবেশের পরিবেশে মুদ্রণ করতে ব্যবহার করি তবে এসটিওআউট-এ মুদ্রণ করুন।


4
"| tee test.log"পুরানো আউটপুটগুলি ওভাররাইট করে দেবে, "| tee -a test.log"পরিবর্তে হতে পারে
02

13

যদিও আমি অন্যান্য পরামর্শগুলি বেশ পছন্দ করি, আমি দেখতে পেয়েছিলাম যে আমার এই একই সমস্যা রয়েছে তবে এসটিডিআরআর এবং ফাইলের জন্য বিভিন্ন লগিং স্তর রাখার সক্ষমতা চেয়েছিলাম।

আমি একটি রাউটিং কৌশলটি শেষ করেছি যা আইও স্তরের চেয়ে লগার স্তরে মাল্টিপ্লেক্সগুলি তৈরি করে, যাতে প্রতিটি লগার স্বতন্ত্র লগ-স্তরে কাজ করতে পারে:

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)

4
আমি এই সমাধানটি সবচেয়ে ভাল পছন্দ করি কারণ এটি (1) সাধারণ, এবং (2) সবকিছুতে কোনও ফাইল যায় তা ধরে না রেখে আপনার লগার ক্লাসগুলি পুনরায় ব্যবহার করতে উত্সাহিত করে। আমার ক্ষেত্রে আমি স্টলআউট এবং গ্রেলগের জন্য একটি গেল্ফ অ্যাপেন্ডারে লগইন করতে চাই। MultiLogger@Dz বর্ণনা করার মতো একটি হ'ল একটি দুর্দান্ত ফিট। ভাগ করে নেওয়ার জন্য ধন্যবাদ!
এরিক ক্রামার

সিউডোভেরিয়েবলগুলি (সেটার / গেটারস) পরিচালনা করতে বিভাগ যুক্ত করা হয়েছে
এরিক ক্রামার

11

আপনি সরাসরি লগারে একাধিক ডিভাইস লগিং কার্যকারিতা যুক্ত করতে পারেন:

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')

9

@ জোনাস054 এর উত্তরে অনুপ্রাণিত হয়ে এখানে আরও একটি বাস্তবায়ন ।

এটি অনুরূপ একটি প্যাটার্ন ব্যবহার করে Delegator। এইভাবে আপনাকে যে সমস্ত পদ্ধতিটি অর্পণ করতে চান তা আপনাকে তালিকাভুক্ত করতে হবে না, কারণ এটি লক্ষ্যবস্তুগুলির যে কোনও একটিতে সংজ্ঞায়িত সমস্ত পদ্ধতি নির্ধারণ করবে:

class Tee < DelegateToAllClass(IO)
end

$stdout = Tee.new(STDOUT, File.open("#{__FILE__}.log", "a"))

আপনার এটি লগারের সাথেও ব্যবহার করতে সক্ষম হওয়া উচিত।

প্রতিনিধি_ টো_ল.আরবি এখানে থেকে পাওয়া যায়: https://gist.github.com/TylerRick/4990898



3

উপরে 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

2

আপনি কি স্ট্যান্ডার্ড লগার সীমাবদ্ধ?

যদি না আপনি ব্যবহার করতে পারেন 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

একটি সুবিধা: আপনি স্টডআউট এবং ফাইলের জন্য বিভিন্ন লগ-স্তরগুলিও সংজ্ঞায়িত করতে পারেন।


1

অন্যান্য লোকেরা ইতিমধ্যে অন্বেষণ করে থাকা "উপ-উপাদানগুলিতে সমস্ত পদ্ধতি হস্তান্তর" করার একই ধারণায় আমি গিয়েছিলাম, তবে তাদের প্রতিটিটির জন্য পদ্ধতির শেষ কলটির রিটার্ন মান ফিরে আসছি। যদি আমি না করতাম তবে এটি ভেঙেছিল 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"

1

আমি একটি সামান্য রুবিগেম লিখেছি যা আপনাকে এই কয়েকটি কাজ করতে অনুমতি দেয়:

# 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"

আপনি গিথুব : টিরবারে কোডটি পেতে পারেন


1

আরও একটি উপায়। আপনি যদি ট্যাগযুক্ত লগিং ব্যবহার করছেন এবং অন্য লগফাইলে পাশাপাশি ট্যাগগুলির প্রয়োজন হয়, আপনি এটি এইভাবে করতে পারেন

# 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(...)
এক্সট্রাস্পিলিটি

0

আরও একটি বিকল্প ;-)

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 ...')

0

আমি মাল্টিআইও পদ্ধতির পছন্দ করি । এটি রুবি লগারের সাথে ভাল কাজ করে । আপনি যদি খাঁটি আইও ব্যবহার করেন তবে এটি কাজ করা বন্ধ করে দেয় কারণ এতে কিছু পদ্ধতির অভাব রয়েছে যা 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 সুতরাং, আমি আশা করি আপনিও এটি দরকারী খুঁজে পেয়েছেন।


0

এটি @ রাডোর সমাধানটির সরলীকরণ।

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")

0

আপনি মণি Loog::Teeথেকে অবজেক্ট ব্যবহার করতে পারেন loog:

require 'loog'
logger = Loog::Tee.new(first, second)

ঠিক আপনি যা খুঁজছেন


0

যদি আপনি ব্যবহারে ঠিক থাকেন 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"

0

আমারও সম্প্রতি এটির প্রয়োজন রয়েছে তাই আমি এমন একটি লাইব্রেরি প্রয়োগ করেছি যা এটি করে। আমি এই স্ট্যাক ওভারফ্লো প্রশ্নটি সন্ধান করেছি, সুতরাং যার প্রয়োজন তার জন্য আমি এটি এখানে রেখে দিচ্ছি: https://github.com/agis/m মাল্টি_ও ।

এখানে উল্লিখিত অন্যান্য সমাধানগুলির সাথে তুলনা করে IO, এটি নিজস্ব একটি বস্তু হতে চেষ্টা করে , তাই এটি অন্যান্য নিয়মিত আইও অবজেক্টগুলির জন্য ফাইল-ড্রপ-ইন প্রতিস্থাপন (ফাইল, সকেট ইত্যাদি) হিসাবে ব্যবহার করা যেতে পারে

এটি বলেছিল, আমি এখনও সমস্ত স্ট্যান্ডার্ড আইও পদ্ধতি বাস্তবায়ন করি নি, তবে সেগুলি আইও শব্দার্থবিজ্ঞানের অনুসরণ করে (উদাহরণস্বরূপ, #writeসমস্ত অন্তর্নিহিত আইও টার্গেটগুলিতে লিখিত বাইটের সংখ্যার যোগফল দেয়)।


-3

আমি মনে করি আপনার STDOUT সমালোচিত রানটাইম তথ্য এবং উত্থাপিত ত্রুটিগুলির জন্য ব্যবহৃত হয়।

সুতরাং আমি ব্যবহার

  $log = Logger.new('process.log', 'daily')

ডিবাগ এবং নিয়মিত লগিং লগ করতে, এবং তারপরে কয়েকটি লিখেছিলেন

  puts "doing stuff..."

যেখানে আমার স্ট্রিপ্ট তথ্য দেখতে হবে যে আমার স্ক্রিপ্টগুলি আদৌ চলছে!

বাহ, মাত্র আমার 10 সেন্ট :-)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.