progstr-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ gem "json"
9
+ gem "multi_json"
10
+
11
+ group :development do
12
+ gem "shoulda", ">= 0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.6.2"
15
+ gem "rcov", ">= 0"
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.2)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ json (1.5.3)
10
+ multi_json (1.0.3)
11
+ rake (0.9.2)
12
+ rcov (0.9.9)
13
+ shoulda (2.11.3)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ bundler (~> 1.0.0)
20
+ jeweler (~> 1.6.2)
21
+ json
22
+ multi_json
23
+ rcov
24
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Hristo Deshev
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ Progstr » logger is a service that collects and manages programmer log entries in the cloud. Most web applications log errors and special external events generated by users or third party systems. Progstr » logger takes away the pain of complex logging system configurations, provides a centralized location for all your log entries and helps you analyze the data you've collected over time. *progstr-ruby* is the Ruby client library that collects log entries and transports them to the Progstr data store.
2
+
3
+ #Installation
4
+
5
+ Install the `progstr-ruby` gem on your system:
6
+
7
+ gem install progstr-ruby
8
+
9
+ Or even better - add it to your bundler configuration by adding this to your Gemfile:
10
+
11
+ gem "progstr-ruby"
12
+
13
+ *progstr-ruby* is a regular Ruby gem that you add to your application. Here is how you integrate it in your project:
14
+
15
+ * Sign up for progstr » logger and obtain an API token. That token is used to identify you against the service. Keep it secret and do not share it with anyone unless you want to let them log messages on your behalf.
16
+ * Install the *progstr-ruby* gem on your system or add it to your bundler configuration.
17
+ * Configure the API token by setting the `Progstr.api_key` property before you start logging:
18
+ <pre>
19
+ Progstr.api_key = "6f413b64-a8e1-4e25-b9e6-d83acf26ccba"
20
+ </pre>
21
+ * (Optional) Set up Rails, so that it sends logs to the Progstr service by changing your respective environment configuration. For example, add this to your `config/environments/production.rb`:
22
+ <pre>
23
+ Progstr.api_key = "6f413b64-a8e1-4e25-b9e6-d83acf26ccba"
24
+ Progstr::RailsLogger.start config
25
+ </pre>
26
+
27
+ #Getting started
28
+
29
+ There are four log severity levels that you can use to log events of different importance:
30
+
31
+ * Info: used to log general information events that can be used for reference or troubleshooting if needed.
32
+ * Warning: something odd happened and somebody needs to know about it.
33
+ * Error: something failed and needs to be fixed.
34
+ * Fatal: the entire application or a critical part of it is not working at all.
35
+
36
+ To log an event you need to create a `Progstr::Logger` object and call some of its info/warn/error/fatal methods. You need to provide the logger source name as a constructor parameter. That will be used to categorize logs and make it easier for you to find specific entries:
37
+
38
+ require 'progstr'
39
+ ...
40
+ ...
41
+ home_log = Progstr::Logger.new("HomeController")
42
+ ...
43
+ home_log.info(message);
44
+ ...
45
+ home_log.warn(message);
46
+ ...
47
+ home_log.error(message);
48
+ ...
49
+ home_log.fatal(message);
50
+
51
+ A `Progstr::Logger` object is really a standard Ruby [Logger](http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/classes/Logger.html). That means you can also check the current log level or do conditional logging using blocks that are evaluated only if the respective level has been enabled. For example, to construct a log message and log it only if info logging has been enabled, you can do this:
52
+
53
+ home_log.info { "Assemble " + "a complex log message here: #{user.name}" }
54
+
55
+ Alternatively, you can override the source name by passing the `progname` parameter to log methods:
56
+
57
+ home_log.warn("other-source") { "Oops, I need to warn somebody!" }
58
+
59
+ If you have configured Rails to send all logs to our service, you can simply use the `Rails.logger` object to log:
60
+
61
+ Rails.logger.info("HomeController#index called")
62
+
63
+ Note: Ruby `Logger` objects also support debug-level logs. `progstr-ruby` will convert those to info logs.
64
+
65
+ # Supported platforms
66
+
67
+ * Ruby 1.8.7 and later
68
+
69
+ # Documentation
70
+
71
+ Available online [here](http://docs.progstr.com).
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "progstr-ruby"
18
+ gem.homepage = "http://github.com/progstr/progstr-ruby"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{progstr.log Ruby client library}
21
+ gem.description = %Q{progstr.log application logging service API client library.}
22
+ gem.email = "hristo@deshev.com"
23
+ gem.authors = ["Hristo Deshev"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "progstr #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,41 @@
1
+ module Progstr
2
+ module Client
3
+ extend self
4
+
5
+ def send(message)
6
+ raise NoApiKeyError if Progstr.api_key.nil?
7
+
8
+ pool.schedule do
9
+ begin
10
+ execute(message)
11
+ rescue Timeout::Error,
12
+ Errno::EINVAL,
13
+ Errno::ECONNRESET,
14
+ Errno::ECONNREFUSED,
15
+ EOFError,
16
+ SocketError,
17
+ Net::HTTPBadResponse,
18
+ Net::HTTPHeaderSyntaxError,
19
+ Net::ProtocolError => error
20
+ #puts "Progstr::Client.send: #{error.message}"
21
+ #puts error.backtrace.join("\r\n")
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def pool
29
+ if (@pool.nil?)
30
+ @pool = ThreadPool.new(2)
31
+ at_exit { @pool.shutdown }
32
+ end
33
+ @pool
34
+ end
35
+
36
+ def execute(message)
37
+ json = MultiJson.encode(message)
38
+ Progstr::HttpClient::post("v1/log", json)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ module Progstr
2
+ class << self
3
+ attr_accessor :host, :path_prefix, :port, :secure, :api_key, :http_open_timeout, :http_read_timeout, :proxy_host, :proxy_port, :proxy_user, :proxy_pass
4
+
5
+ def host
6
+ @host ||= "api.progstr.com"
7
+ end
8
+ def port
9
+ @port || 80
10
+ end
11
+ def path_prefix
12
+ @path_prefix ||= '/'
13
+ end
14
+ def http_open_timeout
15
+ @http_open_timeout ||= 5
16
+ end
17
+
18
+ def http_read_timeout
19
+ @http_read_timeout ||= 15
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,61 @@
1
+ module Progstr
2
+ module HttpClient
3
+ HEADERS = {
4
+ 'Content-type' => 'application/json',
5
+ 'Accept' => 'application/json'
6
+ }
7
+
8
+ class << self
9
+ def post(path, data = '')
10
+ handle_response(http.post(url_path(path), data, headers))
11
+ end
12
+
13
+ protected
14
+
15
+ def protocol
16
+ "http"
17
+ end
18
+
19
+ def url
20
+ URI.parse("#{protocol}://#{Progstr.host}:#{Progstr.port}/")
21
+ end
22
+
23
+ def handle_response(response)
24
+ # do nothing even on errors
25
+ end
26
+
27
+ def headers
28
+ @headers ||= HEADERS.merge({ "X-Progstr-Token" => Progstr.api_key.to_s })
29
+ end
30
+
31
+ def url_path(path)
32
+ Progstr.path_prefix + path
33
+ end
34
+
35
+ def http
36
+ if Thread.current[:http].nil?
37
+ Thread.current[:http] = build_http
38
+ end
39
+ Thread.current[:http]
40
+ end
41
+
42
+ def build_http
43
+ http = Net::HTTP::Proxy(Progstr.proxy_host,
44
+ Progstr.proxy_port,
45
+ Progstr.proxy_user,
46
+ Progstr.proxy_pass).new(url.host, url.port)
47
+
48
+ http.read_timeout = Progstr.http_read_timeout
49
+ http.open_timeout = Progstr.http_open_timeout
50
+ http.use_ssl = false
51
+ http
52
+ end
53
+
54
+ def error_message(response_body)
55
+ Progstr::Json.decode(response_body)["Message"]
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+
@@ -0,0 +1,33 @@
1
+ module Progstr
2
+ class LogMessage
3
+ LEVELS = { :info => 0, :warning => 1, :error => 2, :fatal => 3 }
4
+ LEVELS.default = 0
5
+
6
+ attr_reader :text, :source, :host, :level, :time
7
+
8
+ def initialize(params)
9
+ @text = params[:text]
10
+ @source = params[:source]
11
+ @host = params[:host]
12
+ @level = params[:level]
13
+ @time = params[:time]
14
+ end
15
+
16
+ def to_hash
17
+ {:text => @text, :source => @source, :host => get_host(@host), :level => LEVELS[@level], :time => encode_time(@time)}
18
+ end
19
+
20
+ def to_json
21
+ to_hash.to_json
22
+ end
23
+
24
+ def encode_time(time)
25
+ time ||= Time.now
26
+ (time.to_f * 1000).to_i
27
+ end
28
+
29
+ def get_host(host)
30
+ host || Socket.gethostname || ENV["HOST"] || "Unknown"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ require 'logger'
2
+
3
+ module Progstr
4
+ RubyLogger = Logger
5
+
6
+ class Logger < RubyLogger
7
+ def initialize(source_name = "Unknown")
8
+ device = LoggerDevice.new(source_name)
9
+ super(device)
10
+
11
+ @formatter = device.formatter
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ module Progstr
2
+ class LoggerDevice
3
+ LEVELS_MAP = {
4
+ "INFO" => :info,
5
+ "WARN" => :warning,
6
+ "ERROR" => :error,
7
+ "FATAL" => :fatal
8
+ }
9
+ def initialize(source = nil)
10
+ @source = source || "Unknown"
11
+ end
12
+
13
+ def write(message)
14
+ Progstr::Client::send(message)
15
+ end
16
+
17
+ def close
18
+ end
19
+
20
+ def formatter
21
+ proc do |severity, datetime, progname, msg|
22
+ Progstr::LogMessage.new :text => msg,
23
+ :level => resolve_level(severity),
24
+ :time => datetime,
25
+ :source => resolve_source(progname)
26
+ end
27
+ end
28
+
29
+ def resolve_level(severity)
30
+ LEVELS_MAP[severity] || :info
31
+ end
32
+
33
+ def resolve_source(progname)
34
+ progname || @source
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ module Progstr
2
+ class RailsLogger < Progstr::Logger
3
+ def initialize
4
+ super("Rails")
5
+ end
6
+
7
+ def self.start(rails_config)
8
+ rails_config.after_initialize do
9
+ Rails.logger = rails_config.logger = Progstr::RailsLogger.new
10
+
11
+ #specific loggers for ActionController and ActiveRecord
12
+ ActionController::Base.logger = Progstr::Logger.new("ActionController")
13
+ ActiveRecord::Base.logger = Progstr::Logger.new("ActiveRecord")
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,130 @@
1
+ # Credit goes to Kim Burgestrand:
2
+ # http://burgestrand.se/articles/quick-and-simple-ruby-thread-pool.html
3
+ #
4
+ # Ruby Thread Pool
5
+ # ================
6
+ # A thread pool is useful when you wish to do some work in a thread, but do
7
+ # not know how much work you will be doing in advance. Spawning one thread
8
+ # for each task is potentially expensive, as threads are not free.
9
+ #
10
+ # In this case, it might be more beneficial to start a predefined set of
11
+ # threads and then hand off work to them as it becomes available. This is
12
+ # the pure essence of what a thread pool is: an array of threads, all just
13
+ # waiting to do some work for you!
14
+ #
15
+ # Prerequisites
16
+ # -------------
17
+
18
+ # We need the [Queue](http://rdoc.info/stdlib/thread/1.9.2/Queue), as our
19
+ # thread pool is largely dependent on it. Thanks to this, the implementation
20
+ # becomes very simple!
21
+ # require 'thread'
22
+
23
+ # Public Interface
24
+ # ----------------
25
+
26
+ # `ThreadPool` is our thread pool class. It will allow us to do three operations:
27
+ #
28
+ # - `.new(size)` creates a thread pool of a given size
29
+ # - `#schedule(*args, &job)` schedules a new job to be executed
30
+ # - `#shutdown` shuts down all threads (after letting them finish working, of course)
31
+ class ThreadPool
32
+
33
+ # ### initialization, or `ThreadPool.new(size)`
34
+ # Creating a new `ThreadPool` involves a certain amount of work. First, however,
35
+ # we need to define its’ `size`. It defines how many threads we will have
36
+ # working internally.
37
+ #
38
+ # Which size is best for you is hard to answer. You do not want it to be
39
+ # too low, as then you won’t be able to do as many things concurrently.
40
+ # However, if you make it too high Ruby will spend too much time switching
41
+ # between threads, and that will also degrade performance!
42
+ def initialize(size)
43
+ # Before we do anything else, we need to store some information about
44
+ # our pool. `@size` is useful later, when we want to shut our pool down,
45
+ # and `@jobs` is the heart of our pool that allows us to schedule work.
46
+ @size = size
47
+ @jobs = Queue.new
48
+
49
+ # #### Creating our pool of threads
50
+ # Once preparation is done, it’s time to create our pool of threads.
51
+ # Each thread store its’ index in a thread-local variable, in case we
52
+ # need to know which thread a job is executing in later on.
53
+ @pool = Array.new(@size) do |i|
54
+ Thread.new do
55
+ Thread.current[:id] = i
56
+
57
+ # We start off by defining a `catch` around our worker loop. This
58
+ # way we’ve provided a method for graceful shutdown of our threads.
59
+ # Shutting down is merely a `#schedule { throw :exit }` away!
60
+ catch(:exit) do
61
+ # The worker thread life-cycle is very simple. We continuously wait
62
+ # for tasks to be put into our job `Queue`. If the `Queue` is empty,
63
+ # we will wait until it’s not.
64
+ loop do
65
+ # Once we have a piece of work to be done, we will pull out the
66
+ # information we need and get to work.
67
+ job, args = @jobs.pop
68
+ job.call(*args)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ # ### Work scheduling
76
+
77
+ # To schedule a piece of work to be done is to say to the `ThreadPool` that you
78
+ # want something done.
79
+ def schedule(*args, &block)
80
+ # Your given task will not be run immediately; rather, it will be put
81
+ # into the work `Queue` and executed once a thread is ready to work.
82
+ @jobs << [block, args]
83
+ end
84
+
85
+ # ### Graceful shutdown
86
+
87
+ # If you ever wish to close down your application, I took the liberty of
88
+ # making it easy for you to wait for any currently executing jobs to finish
89
+ # before you exit.
90
+ def shutdown
91
+ # A graceful shutdown involves threads exiting cleanly themselves, and
92
+ # since we’ve defined a `catch`-handler around the threads’ worker loop
93
+ # it is simply a matter of throwing `:exit`. Thus, if we throw one `:exit`
94
+ # for each thread in our pool, they will all exit eventually!
95
+ @size.times do
96
+ schedule { throw :exit }
97
+ end
98
+
99
+ # And now one final thing: wait for our `throw :exit` jobs to be run on
100
+ # all our worker threads. This call will not return until all worker threads
101
+ # have exited.
102
+ @pool.map(&:join)
103
+ end
104
+ end
105
+
106
+ # Demonstration
107
+ # -------------
108
+ # Running this file will display how the thread pool works.
109
+ if $0 == __FILE__
110
+ # - First, we create a new thread pool with a size of 10. This number is
111
+ # lower than our planned amount of work, to show that threads do not
112
+ # exit once they have finished a task.
113
+ p = ThreadPool.new(10)
114
+
115
+ # - Next we simulate some workload by scheduling a large amount of work
116
+ # to be done. The actual time taken for each job is randomized. This
117
+ # is to demonstrate that even if two tasks are scheduled approximately
118
+ # at the same time, the one that takes less time to execute is likely
119
+ # to finish before the other one.
120
+ 20.times do |i|
121
+ p.schedule do
122
+ sleep rand(4) + 2
123
+ puts "Job #{i} finished by thread #{Thread.current[:id]}"
124
+ end
125
+ end
126
+
127
+ # - Finally, register an `at_exit`-hook that will wait for our thread pool
128
+ # to properly shut down before allowing our script to completely exit.
129
+ at_exit { p.shutdown }
130
+ end
data/lib/progstr.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "multi_json"
2
+ require "socket"
3
+ require "net/http"
4
+ require "net/https"
5
+ require "thread"
6
+ require "logger"
7
+
8
+ require "progstr/config"
9
+ require "progstr/threadpool"
10
+ require "progstr/log_message"
11
+ require "progstr/client"
12
+ require "progstr/httpclient"
13
+ require "progstr/logger_device"
14
+ require "progstr/logger"
15
+ require "progstr/rails_logger"
16
+
17
+ class NoApiKeyError < StandardError; end
@@ -0,0 +1,10 @@
1
+ require "progstr"
2
+
3
+ Progstr.api_key = "DEMO"
4
+
5
+ logger = Progstr::Logger.new("console-script")
6
+ logger.info("Something funny")
7
+ logger.info("source-override") { "Something funny with custom source" }
8
+
9
+ rails_logger = Progstr::RailsLogger.new
10
+ rails_logger.info("Something funny in Rails-land.")
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'progstr'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,24 @@
1
+ require 'helper'
2
+
3
+ class TestFormatter < Test::Unit::TestCase
4
+ should "serialize level" do
5
+ device = Progstr::LoggerDevice.new
6
+ formatter = device.formatter
7
+
8
+ yesterday = Time.now - 1 * 60 * 60 * 24
9
+ message = formatter.call("WARN", yesterday, "progname", "message body")
10
+ assert_equal "progname", message.source
11
+ assert_equal :warning, message.level
12
+ assert_equal "message body", message.text
13
+ assert_equal yesterday, message.time
14
+ end
15
+
16
+ should "infer progname from constructor" do
17
+ device = Progstr::LoggerDevice.new("default-progname")
18
+ formatter = device.formatter
19
+
20
+ yesterday = Time.now - 1 * 60 * 60 * 24
21
+ message = formatter.call("WARN", yesterday, nil, "message body")
22
+ assert_equal "default-progname", message.source
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ require 'helper'
2
+
3
+ class TestProgstrRuby < Test::Unit::TestCase
4
+ should "serialize text and source" do
5
+ message = Progstr::LogMessage.new :text => "test message",
6
+ :source => "progstr.something",
7
+ :host => "dev-machine"
8
+ assert_equal "test message", message.to_hash[:text]
9
+ assert_equal "progstr.something", message.to_hash[:source]
10
+ assert_equal "dev-machine", message.to_hash[:host]
11
+ end
12
+
13
+ should "serialize level" do
14
+ message = Progstr::LogMessage.new :level => :info
15
+ assert_equal 0, message.to_hash[:level]
16
+ end
17
+
18
+ should "serialize time in millis since epoch start (UTC)" do
19
+ now = Time.now
20
+ nowMillis = (now.to_f * 1000).to_i
21
+ message = Progstr::LogMessage.new :time => now
22
+ assert_equal nowMillis, message.to_hash[:time]
23
+ end
24
+
25
+ should "get current time if not given" do
26
+ message = Progstr::LogMessage.new({})
27
+ assert message.to_hash[:time] > 0, "time not valid"
28
+ end
29
+
30
+ should "get machine name" do
31
+ message = Progstr::LogMessage.new({})
32
+ assert message.to_hash[:host].to_s.size > 0, "host name not inferred"
33
+ end
34
+
35
+ should "serialize to json" do
36
+ newYear = Time.utc(2011, 1, 1)
37
+ message = Progstr::LogMessage.new :text => "test message",
38
+ :source => "progstr.something",
39
+ :host => "dev-machine",
40
+ :level => :error,
41
+ :time => newYear
42
+
43
+ json = MultiJson.encode(message)
44
+ assert_match /"source":"progstr.something"/, json
45
+ assert_match /"host":"dev-machine"/, json
46
+ assert_match /"text":"test message"/, json
47
+ assert_match /"level":2/, json
48
+ assert_match /"time":\d+/, json
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: progstr-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Hristo Deshev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-12 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &15006000 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *15006000
25
+ - !ruby/object:Gem::Dependency
26
+ name: multi_json
27
+ requirement: &15005520 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *15005520
36
+ - !ruby/object:Gem::Dependency
37
+ name: shoulda
38
+ requirement: &15005040 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *15005040
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: &15004560 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *15004560
58
+ - !ruby/object:Gem::Dependency
59
+ name: jeweler
60
+ requirement: &15004080 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.6.2
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *15004080
69
+ - !ruby/object:Gem::Dependency
70
+ name: rcov
71
+ requirement: &15003600 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *15003600
80
+ description: progstr.log application logging service API client library.
81
+ email: hristo@deshev.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files:
85
+ - LICENSE.txt
86
+ - README.md
87
+ files:
88
+ - .document
89
+ - Gemfile
90
+ - Gemfile.lock
91
+ - LICENSE.txt
92
+ - README.md
93
+ - Rakefile
94
+ - VERSION
95
+ - lib/progstr.rb
96
+ - lib/progstr/client.rb
97
+ - lib/progstr/config.rb
98
+ - lib/progstr/httpclient.rb
99
+ - lib/progstr/log_message.rb
100
+ - lib/progstr/logger.rb
101
+ - lib/progstr/logger_device.rb
102
+ - lib/progstr/rails_logger.rb
103
+ - lib/progstr/threadpool.rb
104
+ - script/test-post.rb
105
+ - test/helper.rb
106
+ - test/test_formatter.rb
107
+ - test/test_progstr.rb
108
+ homepage: http://github.com/progstr/progstr-ruby
109
+ licenses:
110
+ - MIT
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ segments:
122
+ - 0
123
+ hash: -1547365430839715510
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.6
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: progstr.log Ruby client library
136
+ test_files: []