Giter Club home page Giter Club logo

sidekiq-statistic's Introduction

Sidekiq::Statistic

Build Status Code Climate Gitter

Improved display of statistics for your Sidekiq workers and jobs.

Screenshots

Index page:

sidekiq-history_index

Worker page with table (per day):

sidekiq-history_worker

Installation

Add this line to your application's Gemfile:

gem 'sidekiq-statistic'

And then execute:

$ bundle

Usage

Using Rails

Read Sidekiq documentation to configure Sidekiq Web UI in your routes.rb.

When Sidekiq Web UI is active you're going be able to see the option Statistic on the menu.

Using a standalone application

Read Sidekiq documentation to configure Sidekiq in your Rack server.

Next add require 'sidekiq-statistic' to your config.ru.

# config.ru
require 'sidekiq/web'
require 'sidekiq-statistic'

use Rack::Session::Cookie, secret: 'some unique secret string here'
run Sidekiq::Web

Configuration

The Statistic configuration is an initializer that GEM uses to configure itself. The option max_timelist_length is used to avoid memory leak, in practice, whenever the cache size reaches that number, the GEM is going to remove 25% of the key values, avoiding inflating memory.

Sidekiq::Statistic.configure do |config|
  config.max_timelist_length = 250_000
end

Supported Sidekiq versions

Statistic support the following Sidekiq versions:

  • Sidekiq 6.
  • Sidekiq 5.
  • Sidekiq 4.
  • Sidekiq 3.5.

JSON API

/api/statistic.json

Returns statistic for each worker.

Params:

  • dateFrom - Date start (format: yyyy-mm-dd)
  • dateTo - Date end (format: yyyy-mm-dd)

Example:

$ curl http://example.com/sidekiq/api/statistic.json?dateFrom=2015-07-30&dateTo=2015-07-31

# =>
  {
    "workers": [
      {
        "name": "Worker",
        "last_job_status": "passed",
        "number_of_calls": {
          "success": 1,
          "failure": 0,
          "total": 1
        },
        "runtime": {
          "last": "2015-07-31 10:42:13 UTC",
          "max": 4.002,
          "min": 4.002,
          "average": 4.002,
          "total": 4.002
        }
      },

      ...
    ]
  }

/api/statistic/:worker_name.json

Returns worker statistic for each day in range.

Params:

  • dateFrom - Date start (format: yyyy-mm-dd)
  • dateTo - Date end (format: yyyy-mm-dd)

Example:

$ curl http://example.com/sidekiq/api/statistic/Worker.json?dateFrom=2015-07-30&dateTo=2015-07-31

# =>
{
  "days": [
    {
      "date": "2015-07-31",
      "failure": 0,
      "success": 1,
      "total": 1,
      "last_job_status": "passed",
      "runtime": {
        "last": null,
        "max": 0,
        "min": 0,
        "average": 0,
        "total": 0
      }
    },

    ...
  ]
}

Update statistic inside middleware

You can update your worker statistic inside middleware. For this you should to update sidekiq:statistic redis hash. This hash has the following structure:

  • sidekiq:statistic - redis hash with all statistic
    • yyyy-mm-dd:WorkerName:passed - count of passed jobs for Worker name on yyyy-mm-dd
    • yyyy-mm-dd:WorkerName:failed - count of failed jobs for Worker name on yyyy-mm-dd
    • yyyy-mm-dd:WorkerName:last_job_status - string with status (passed or failed) for last job
    • yyyy-mm-dd:WorkerName:last_time - date of last job performing
    • yyyy-mm-dd:WorkerName:queue - name of job queue (default by default)

For time information you should push the runtime value to yyyy-mm-dd:WorkerName:timeslist redis list.

How it works

Big image 'how it works'

how-it-works

Contributing

  1. Fork it ( https://github.com/davydovanton/sidekiq-statistic/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

sidekiq-statistic's People

Contributors

anfinil avatar artofhuman avatar brunnohenrique avatar davydovanton avatar dougmrqs avatar emersonmanabuaraki avatar fabn avatar felixbuenemann avatar gabrielrumiranda avatar garethson avatar gquirino avatar hschne avatar kostadriano avatar luong-komorebi avatar mperham avatar msroot avatar petergoldstein avatar rbuubr avatar rda1902 avatar salbertson avatar sancopanco avatar spinx avatar stan avatar timurb avatar v-gutierrez avatar vp993 avatar vriazantsev-mobidev avatar wenderjean avatar wflanagan avatar yousysadmin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sidekiq-statistic's Issues

Log to STDOUT

Is there a way to configure this?

Base on documentation, the log_file seems to need a log file to read from.
If I have all my log logging to stdout following Docker conventions, could we actually get that in the worker log section as well?

Redis key nesting inverted

The nesting of the redis keys is inverted compared to redis, eg. sidekiq uses my_app:sidekiq:stat:processed:2015-05-31, but sidekiq-statistic uses my_app:sidekiq:2015-08-19:Foo::BarWorker:timeslist.

The expected nesting would be: my_app:sidekiq:timeslist:Foo::BarWorker:2015-08-19.

Outlier detection?

I like this project seems like a cool idea!

Just wondering would y'all be interested in an outlier detection pull request? Not sure if that's outside the scope of this project or not.

My thinking would be to introduce mean absolute deviation (or MAD), and median to the time statistics hash. Then from there use the industry standard 3 threshold for a pretty robust and simple outlier detection model. Graphically I would just annotate the outliers. It would be cool to somehow tie this to alerting but I feel that might be way out of scope.

Thoughts / concerns?

Cheers โœจ

ArgumentError - comparison of String with 0.027 failed

Hey guys. I came across this error today:

App 9754 stderr: 2015-09-23 17:37:00 - ArgumentError - comparison of String with 0.027 failed:
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/runtime.rb:25:in `each'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/runtime.rb:25:in `min'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/runtime.rb:25:in `min_runtime'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/runtime.rb:14:in `values_hash'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/workers.rb:13:in `block in display'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/workers.rb:7:in `map'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/statistic/workers.rb:7:in `display'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/side
kiq-statistic-1.1.0/lib/sidekiq/statistic/web_extension.rb:32:in `block in registered'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1610:in `call'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1610:in `block in compile!'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:974:in `[]'
App 9754 stderr:        /home/user/apps/myapp/shared/bundle/ruby/2.1.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:974:in `block (3 levels) in route!'

I'm using:

  • Sinatra 1.4.6
  • ruby 2.1.2p95
  • Sidekiq 3.4.1
  • Sidekiq statistic 1.1.0
  • Sidekiq failures 0.4.2

Any idea what could it be? I'll see if I can take a look at the code this weekend.

Properly handle namespaced Workers

The plugin currently does not properly handle worker classes, which are nested in a module, eg. Foo::BarWorker and Foo::BazWorker wil display as a single entry Foo with wrong stats in the WorkersTable.

My guess is that this is because : is also used as the separator for the redis keys (eg. my_app_production:sidekiq:2015-08-19:Foo::BarWorker:timeslist.

statistic page can't load js & css files

Trying to get the gem running against sidekiq 4.2.2 on a rails 4.2.7.1 app

The statistics page is visible on the web interface of sidekiq but when clicked on it renders incompletely - the css & js file requests to the server return a 500 error with the top of the stack trace saying NameError - uninitialized constant Sidekiq::WebAction::CONTENT_TYPE:

any help is much appreciated

history with multiple Worker Classes raise runtime error

When running more than one worker class, sidekiq-history raises NoMethodError: undefined methodsymbolize_keys' for nil:NilClass` when recording statistics.

lib/sidekiq/history/middleware.rb:50

To reproduce:

  1. Execute jobs with SendEmailWorker one or more times
  2. Executes jobs with SendTwitterWorker once
  3. See 'SendTwitterWorker' fail, with the 'retries' tab in sidekiq-web, showing the error message NoMethodError: undefined method symbolize_keys' for nil:NilClass
  4. if you execute workers with (backtrace: true), then the error is at lib/sidekiq/history/middleware.rb:50

Total time not working?

Hi there,

I deployed sidekiq-statistic 30 minutes ago on a production app, and the Time(sec) column doesn't seem to match the job count * average formula I'd expect:

(worker names voluntarily truncated)

Workers with more than 1 job count have a total run time close to the average run time, instead of being closer to 100, 200 or 300 times the average run time.

Am I misunderstanding how to read these numbers or did I find an issue with this gem?

Issue with custom Date default format

Sidekiq v3.5.0 - Sidekiq/Statistic v1.1

I'm using a custom Date::DATE_FORMATS[:default] in my application, and this breaks the expectation that to_s for a Date will always return something formatted as "%Y-%m-%d".

The following would fix this (and clarify my point) :

Replacing (@end_date..@start_date).map(&:to_s) by (@end_date..@start_date).collect{|date| date.strftime "%Y-%m-%d"} in https://github.com/davydovanton/sidekiq-statistic/blob/master/lib/sidekiq/statistic/base.rb#L44

Replacing worker_key = "#{time.to_date}:#{status.delete :class}" by worker_key = "#{time.strftime "%Y-%m-%d"}:#{status.delete :class}" in https://github.com/davydovanton/sidekiq-statistic/blob/master/lib/sidekiq/statistic/middleware.rb#L32

Note that I raised a similar issue with Sidekiq sidekiq/sidekiq#2559

I'm not sure if this should be considered an issue with your code or not, I'll leave it to you to decide

[Feature request] New metrics: EWMA and percentiles

Hi everyone!

First of all, thanks and congratulations for sidekiq-statistic!
It's awesome and very useful!

I'm opening this PR to suggest some new metrics: Exponential moving average (EWMA) and percentiles of the worker's processing times.

The first one is similar to Unix's load average and would be very useful in environments with tens of thousands Sidekiq executions per day.
In these scenarios, the single "all-day average" would not be changed in the short-term if the workers take longer to do their jobs.

And the percentiles metrics (maybe p50, p75, p90 and p99?) would be useful in scenarios where the standard deviation of worker's executions is very large.

What do you think about it?

use deprecation command

When I open url: sidekiq/history in my log I see:

Passing 'disconnect!' command to redis as is; blind passthrough has been deprecated and will be removed in redis-namespace 2.0 (at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/connection_pool-2.1.2/lib/connection_pool/timed_stack.rb:133:in `block in discard!')

Part of Gemfile.lock:

sidekiq (3.2.6)
  celluloid (= 0.15.2)
  connection_pool (>= 2.0.0)
  json
  redis (>= 3.0.6)
  redis-namespace (>= 1.3.1)
sidekiq-history (0.0.5)
  sidekiq (>= 3.0.0)
sidekiq-limit_fetch (2.2.6)
  sidekiq (>= 2.6.5, < 4.0)
sidetiq (0.6.1)
  celluloid (>= 0.14.1)
  ice_cube (~> 0.12.0)
  sidekiq (>= 2.16.0)

String can't be coerced into Float

23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/runtime.rb:40:in `+'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/runtime.rb:40:in `each'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/runtime.rb:40:in `inject'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/runtime.rb:40:in `average_runtime'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/runtime.rb:15:in `values_hash'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/workers.rb:13:in `block in display'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/workers.rb:7:in `map'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/statistic/workers.rb:7:in `display'
23:46:56 web.1     | 	/usr/local/bundle/gems/sidekiq-statistic-1.2.0/lib/sidekiq/statistic/web_extension.rb:32:in `block in registered'

Filtering log by JID

Hello!

I haven't looked at this project carefully but one of the screenshots looks very interesting to me. I mean a worker log.

The problem that I often face in my work is to look at what happened in the context of one job. Sidekiq logs are not human-friendly since many threads all write to one log file. Filtering logs by a worker class is not enough โ€” I also need a convenient way to filter a log by JID (for now, I just fgrep by particular JID in my sidekiq.log).

I also see a 'Search text in log file` input box in this screenshot. So I think it would be useful to make JID in log clickable and on click simply insert JID in the text field and perform the search.

What do you think?

Release plan

  • Add option with log path for not default logfile [done]
  • Add custom assets [done]
  • Catch the error log of absence [done]
  • Improve log web UI page [done]
  • Add find in log [done]
  • Add max time row to index table [done]
  • Add min time row to index table [done]
  • Specific color for each worker name [done]
  • Add worker table for each day [done]
  • Add live reload for index page [done]
  • Fix displaying date on index page [done]
  • Fix displaying last run time [done]
  • Add row with status for last worker job [done]
  • Show information for any time interval [done]
  • Fix not thread safe middleware [done]
  • Support AJ [done]
  • Read first 1000 lines from logfile [done]
  • Add external JSON API [done]
  • Localizations [done]
  • Realtime chart for each worker [done]
  • Add filters (by worker) for realtime chart [done]
  • Save job runtime in redis list #33 (comment) [done]
  • Update documentation [done]
  • Integration with other services (like newrelic) (undefined feature)
  • More system informations (undefined feature, ask from @mperham)
  • Add to table next runtime (undefined feature)
  • Sidekiq process from nix system tools (undefined feature)

Sorting workers in graph tooltip

I noted, that workers in graph tooltips don't sorted eather by name or by execution count. Maybe sorting workers by execution count is good idea?

Getting Rack::Timeout::RequestTimeoutException

Getting timeout issue on Heroku, I am guessing its because of the data size. How to resolve this issue?

Also, if I need to clean the statistics data, would this work? I wanna run this on prod, and not clean up queue data, just remove stats data.

Sidekiq.redis do |conn|
  conn.del('sidekiq:statistic')
end

undefined method `reverse!' for nil:NilClass (NoMethodError)

I try to run the plugin as in standalone mode as it described in the manual, but got this error

require 'sidekiq/web'
require 'sidekiq-statistic'

use Rack::Session::Cookie, secret: 'some-unique-secret-string-here'
Sidekiq::Web.instance_eval { @middleware.reverse! } # Last added, First Run
#
run Sidekiq::Web
config.ru:5:in `block (2 levels) in <main>': undefined method `reverse!' for nil:NilClass (NoMethodError)

Ruby 2.3.1

The gem does not scale

We deployed this gem on a fairly busy sidekiq app. It wound up shooting our memory usage up to 1.9 GB after 3 weeks. After removing sidekiq-statistic and all of the large-sized :timeslist stores, it brought our memory usage down to under 30 MB. I'm not sure if there is a solution for this, maybe limiting the data that can be retrieved over time, however it should be known that sidekiq-statistic is definitely not suitable for high usage apps.

Moving workers between queues

I know, that worker management is not related with it's statistics, but sometimes sidekiq users need to do move scheduled and queued workers into other queues. Is to possible to implement this functionality is this gem?

timeslist does not expire

https://github.com/davydovanton/sidekiq-statistic/blob/master/lib/sidekiq/statistic/middleware.rb#L40

The timeslist should be expired after some amount of time and (I'd suggest) the times aggregated into a much more compact form. The Web UI could store hourly aggregates per worker.

If I were implementing this, I'd compact the timeslists hourly. The compact form could store:

execution count
average time
standard deviation
98th percentile
etc

So instead of a list of thousands of numbers, it would be converted into a hash with 4-6 numbers per hour. You could expire the hashes after one month, giving the user a nice recent history to compare.

Truncated graph labels

If you have many workers, you can see something like this
screen

As you can see, labes is trancated frome above

Choose date selector for gem

I want to add date selector for worker table, charts, etc. But I have a little problem. I don't know what the best design solutions (and libraries) for this type date selectors. Now I think about slider like as jQRangeSlider.

Therefore it's very important for me to see your ideas and suggestions
Thanks.
/cc @mperham

ArgumentError - argument out of range

Using sidekiq enterprise 3.5.3. Tried sidekiq-statisic 1.1.0, 1.2.0 and HEAD (f27fcdf).

2015-11-23 13:44:51 - ArgumentError - argument out of range:
    /usr/lib/ruby/2.1.0/time.rb:264:in `local'
    /usr/lib/ruby/2.1.0/time.rb:264:in `make_time'
    /usr/lib/ruby/2.1.0/time.rb:331:in `parse'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension_helper.rb:9:in `formate_date'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:80:in `block (2 levels) in singleton class'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:77:in `each'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:77:in `block in singleton class'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:27:in `instance_eval'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:27:in `singleton class'
    /srv/core/shared/bundle/ruby/2.1.0/bundler/gems/sidekiq-statistic-f27fcdfe6fc0/lib/sidekiq/statistic/web_extension.rb:25:in `__tilt_174714020'

Add locale files for each language

  • cs.yml
  • da.yml
  • de.yml
  • el.yml
  • en.yml
  • es.yml
  • fr.yml
  • hi.yml
  • it.yml
  • ja.yml
  • ko.yml
  • nl.yml
  • no.yml
  • pl.yml
  • pt-br.yml
  • pt.yml
  • ru.yml
  • sv.yml
  • ta.yml
  • uk.yml
  • zh-cn.yml
  • zh-tw.yml

Cannot read property of undefined

Getting some JS issues, but unable to resolve.

Steps to replicate:

  1. Installed gem
  2. Go to Sidekiq interface and click on Statistics.

Error:
statistic.js:formatted:1738Uncaught TypeError: Cannot read property 'draw' of undefined
statistic.js:formatted:1722Uncaught TypeError: Cannot read property 'update' of undefined

Understanding stats

Image

I'm not sure what some of the columns mean. First five are clear, but from there on numbers change over time up and down and not sure what the relations are among them. Could any explain what are they referring to? (Time(sec), Average(sec), etc.)

June review feedback

Hi Anton, this looks amazing so far. You've got 90% of the functionality done already; I'm very impressed! Here's a couple of issues I noted:

  1. The project needs to be renamed to sidekiq_history or maybe something more distinctive. Right now I have to use gem 'sidekiq_history', require: 'sidekiq-history' in the Gemfile, which is really awkward. Maybe "worker-history", "job-history" or "sidekiq-chronicle"? Naming is hard.
  2. Making the user configure the logfile location should be a last resort, you can make the code a little smarter so it just works more often. A hack lets you look into the logger to find the filename it is actually using: Sidekiq.logger.instance_variable_get(:@logdev).filename
  3. Unfortunately your history storage is not thread-safe and will lose data under heavy load. You are pulling data out of Redis, mutating it and then pushing it back to Redis. If multiple threads are doing this, they can lose changes. You'll need to redesign your history storage to use multi or atomic operations, like incr, hincrby, etc. In general, avoid using JSON; store the data in native Redis datatypes if possible.

The last one is the major issue and solving it will teach you a lot more about Redis and threading. You might start by writing a test which hammers the middleware with 20-30 concurrent threads and verifying the history statistics are wrong. Once you've shown that, you can redesign the storage and see the test pass, even under heavy load. I wrote a similar test for Dalli years ago to prove the Dalli::Client threadsafe in MRI and JRuby.

Commit access

Would you mind giving me commit access so I can push pull requests to you?

Does this gem play nicely with multiple sidekiq processes?

We have two sidekiq processes running and it only seems to see our main queue/the project where the sidekiq-web gem is configured.

The sidekiq web interface shows us jobs processing through all of Sidekiq's scope of worker queues but this gem doesn't seem to see all queues?

processes messages per queue

Hi @davydovanton
As discussed here sidekiq/sidekiq#1626 (comment) I am looking for statistics about the number of messages processed per queue. Now this is only recorded for the complete sidedkiq instance. Preferably these stats should be exposed by a json API call.
Right now I created a custom sidekiq module (only a few lines) to expose the queue length and latency of all queues. It would be great if exposing the number of messaged proccess per queue could be incorporated.

Sidekiq 4 support

Any plans of releasing this fix, I noticed theres already a commit for this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.