Tôi có một máy chủ web nhỏ mà tôi đã viết với Sinatra. Tôi muốn có thể đăng nhập tin nhắn vào một tệp nhật ký. Tôi đã đọc qua http://www.sinatrarb.com/api/index.html và www.sinatrarb.com/intro.html và tôi thấy rằng Rack có tên Rack :: CommonLogger, nhưng tôi không thể tìm thấy bất kỳ ví dụ nào về cách nó có thể được truy cập và sử dụng để ghi nhật ký. Ứng dụng của tôi rất đơn giản vì vậy tôi đã viết nó như là một DSL cấp cao nhất, nhưng tôi có thể chuyển sang phân lớp nó từ SinatraBase nếu đó là một phần của những gì được yêu cầu.Sử dụng Rack :: CommonLogger in Sinatra
Trả lời
Rack::CommonLogger
sẽ không cung cấp nhật ký cho ứng dụng chính của bạn, nó sẽ chỉ ghi lại yêu cầu như Apache sẽ thực hiện.
Kiểm tra mã của mình: https://github.com/rack/rack/blob/master/lib/rack/common_logger.rb
Tất cả Rack
ứng dụng có gọi phương thức mà có được ấy gọi với HTTP Request env, nếu bạn đánh dấu vào phương pháp gọi của middleware này đây là những gì sẽ xảy ra:
def call(env)
began_at = Time.now
status, header, body = @app.call(env)
header = Utils::HeaderHash.new(header)
log(env, status, header, began_at)
[status, header, body]
end
@app
Trong trường hợp này là ứng dụng chính, phần mềm trung gian chỉ đăng ký thời gian yêu cầu bắt đầu, sau đó lớp trung gian của bạn nhận được [trạng thái, tiêu đề, nội dung] ba và sau đó gọi phương thức nhật ký riêng với các tham số đó , trả lại cùng một gấp ba lần Trang được trả lại ngay từ đầu.
Phương pháp logger
đi như thế:
def log(env, status, header, began_at)
now = Time.now
length = extract_content_length(header)
logger = @logger || env['rack.errors']
logger.write FORMAT % [
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
env["REMOTE_USER"] || "-",
now.strftime("%d/%b/%Y %H:%M:%S"),
env["REQUEST_METHOD"],
env["PATH_INFO"],
env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
env["HTTP_VERSION"],
status.to_s[0..3],
length,
now - began_at ]
end
Như bạn có thể nói, phương pháp log
chỉ lấy một số thông tin từ env yêu cầu, và đăng nhập vào trên một logger được chỉ định vào cuộc gọi constructor, nếu có không dụ logger sau đó nó đi vào rack.errors
logger (có vẻ như có một mặc định)
cách sử dụng nó (trong bạn config.ru
):
logger = Logger.new('log/app.log')
use Rack::CommonLogger, logger
run YourApp
Nếu bạn muốn có một logger phổ biến ở tất cả các ứng dụng của bạn, bạn có thể tạo một middleware logger đơn giản:
class MyLoggerMiddleware
def initialize(app, logger)
@app, @logger = app, logger
end
def call(env)
env['mylogger'] = @logger
@app.call(env)
end
end
Để sử dụng nó, trên config.ru
của bạn:
logger = Logger.new('log/app.log')
use Rack::CommonLogger, logger
use MyLoggerMiddleware, logger
run MyApp
Hope this helps.
Tôi đi theo những gì tôi tìm thấy trên blog bài này - trích dưới đây
require 'rubygems'
require 'sinatra'
disable :run
set :env, :production
set :raise_errors, true
set :views, File.dirname(__FILE__) + '/views'
set :public, File.dirname(__FILE__) + '/public'
set :app_file, __FILE__
log = File.new("log/sinatra.log", "a")
STDOUT.reopen(log)
STDERR.reopen(log)
require 'app'
run Sinatra.application
sau đó sử dụng puts
hoặc print
. Nó làm việc cho tôi.
đó làm việc, nhưng tôi thực sự muốn tìm hiểu làm thế nào để sử dụng rack :: CommonLogger để gửi tin nhắn được định dạng với thời gian. –
Trong config.ru
của bạn:
root = ::File.dirname(__FILE__)
logfile = ::File.join(root,'logs','requests.log')
require 'logger'
class ::Logger; alias_method :write, :<<; end
logger = ::Logger.new(logfile,'weekly')
use Rack::CommonLogger, logger
require ::File.join(root,'myapp')
run MySinatraApp.new # Subclassed from Sinatra::Application
tôi thử giải pháp của bạn, và nó hoạt động. tôi tự hỏi tại sao nó phải ở trong config.ru? – Chamnap
một tập tin những điều tôi không 100% trên đó, bạn sẽ nhớ bình luận về những gì/lý do tại sao một số dòng là có xin vui lòng? –
class ErrorLogger
def initialize(file)
@file = ::File.new(file, "a+")
@file.sync = true
end
def puts(msg)
@file.puts
@file.write("-- ERROR -- #{Time.now.strftime("%d %b %Y %H:%M:%S %z")}: ")
@file.puts(msg)
end
end
class App < Sinatra::Base
if production?
error_logger = ErrorLogger.new('log/error.log')
before {
env["rack.errors"] = error_logger
}
end
...
end
Mở lại STDOUT và chuyển hướng nó vào một tập tin không phải là một ý tưởng tốt nếu bạn sử dụng hành khách. Nó gây ra trong trường hợp của tôi rằng Hành khách không bắt đầu. Đọc https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems#stdout-redirection cho vấn đề này.
Đây sẽ là một cách đúng đắn thay vì:
logger = ::File.open('log/sinatra.log', 'a+')
Sinatra::Application.use Rack::CommonLogger, logger
Không phải dòng đầu tiên của cuộc gọi MyLoggerMiddleware # (env) là: env ['rack.errors'] = @logger ? –
Ngoài ra, tôi không muốn đăng nhập mọi yêu cầu, chỉ cảnh báo và thông báo lỗi. Nhưng tôi muốn nó được cấu hình để tôi có thể thiết lập mức độ đăng nhập, như trong "gỡ rối", "thông tin", "cảnh báo", "lỗi", ... BTW - Ứng dụng của tôi không phải là một Rails ứng dụng. Không có tệp config.ru. Đó là một ứng dụng Sinatra đơn giản. Tôi đã hy vọng sử dụng một tiêu chuẩn hiện có, nhưng không thể hiểu được đó là gì. Có lẽ tôi phải lấy CommonLogger bạn cho tôi xem và tự mình làm một mình? –
'config.ru' là tệp cấu hình cho Rack, không phải cho Rails. Cả Sinatra và Rails đều dựa trên Rack, vì vậy bạn có thể sử dụng 'config.ru' trong các ứng dụng Sinatra. – jafrog