Giter Club home page Giter Club logo

scout_apm_ruby's Introduction

ScoutApm Ruby Agent

Build Status

A Ruby gem for detailed Rails application performance monitoring 📈. Metrics and transaction traces are reported to Scout, a hosted application monitoring service.

What's the special sauce? 🤔

The Scout agent is engineered to do some wonderful things:

Getting Started

Add the gem to your Gemfile

gem 'scout_apm'

Add a version of the parser gem that supports your version of Ruby. For example, if you're on Ruby 3.3.0:

gem 'parser', '~> 3.3.0.0'

Update your Gemfile

bundle install

Signup for a Scout account and put the provided config file at RAILS_ROOT/config/scout_apm.yml.

Your config file should look like:

common: &defaults
  name: YOUR_APPLICATION_NAME
  key: YOUR_APPLICATION_KEY
  monitor: true

test:
  monitor: false

production:
  <<: *defaults

DevTrace Quickstart

To use DevTrace, our free, no-signup, in-browser development profiler:

  1. Add the gem to your Gemfile:
# Gemfile
gem 'scout_apm'
  1. Start your Rails app with the SCOUT_DEV_TRACE environment variable:
SCOUT_DEV_TRACE=true rails server

How to test gem locally

  • Point your gemfile at your local checkout: gem 'scout_apm', path: '/path/to/scout_apm_ruby
  • Compile native code: cd /path/to/scout_apm_ruby && bundle exec rake compile

Docs

For the complete list of supported frameworks, Rubies, configuration options and more, see our help site.

Help

Email [email protected] if you need a hand.

scout_apm_ruby's People

Contributors

abhishek77in avatar alindeman avatar andriiakulov avatar bf4 avatar biow0lf avatar bjeanes avatar bohdanbenov avatar britto avatar casperisfine avatar chagel avatar composit avatar conarro avatar cschneid avatar danielmorrison avatar dlanderson avatar esparta avatar gustavothecoder avatar ibrahima avatar ioquatix avatar itsderek23 avatar jamie avatar jasonrudolph avatar joaquimadraz avatar jrothrock avatar kxmbrian avatar lancetarn avatar mathieujobin avatar nearapogee avatar rubiety avatar shadwell 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

scout_apm_ruby's Issues

Increase max query length to 16k from 4k

We limit parsing of SQL queries to 4k chars (SQLSanitizer#scrubbed). Suggest we increase this to 16k: this seems like a safe enough increase and would show more details on complex queries that are often slower.

NoMethodError: undefined method `type` for NilClass

A customer is reporting the following error (screenshot from Rollbar):

I haven't yet determined if this is happening on every request or just a specific request.

I believe this is running Rails 5.0.4 and Ruby 2.2.0.

fake_stack_prof swallows forgetting to add stackprof to system

Lost about a half an hour of my day to:

/Users/richardschneeman/.gem/ruby/2.3.1/gems/scout_apm-2.0.0.pre/lib/scout_apm/utils/fake_stack_prof.rb

Turns out the system didn't have stackprof in the Gemfile but I didn't realize because I wasn't getting any errors when trying to directly use StackProf.run.

Maybe try to require it and output some warning code if it cannot be loaded:

begin
  require 'stackprof'
rescue LoadError
  warn "Could not load `stackprof` gem, make sure it's on your system. If your system cannot run stackprof disable this message with SCOUT_DISABLE_STACKPROF_WARNING=1 environment variable" unless ENV["SCOUT_DISABLE_STACKPROF_WARNING"]
end

FEATURE REQUEST: Direct Link to IDE for dev_trace

In order to have a better coding (and troubleshooting) experience, it would be nice to click on a certain line which opens the corresponding LOC in my IDE.

In my example a link to a file and line in my IDE "Rubymine" looks like this:

x-mine://open?file=%{file}&line=%{line}

bildschirmfoto 2017-04-24 um 00 21 45

Fix Capistrano integration for deploy markers

The capistrano deploy hook needs to use scout_apm's app name for the environment the app is being deployed to.

The DeploysController#create identifies the app via the name provided. But, if you have a different app name specified for your local development environment, it will try to associate the deploy with the development app, not the production or staging app.

Correctly name Sidekiq jobs called via `.delay`

Sidekiq ships with an extension that allows Foo.delay.slow_thing, adding .delay to every class to automatically turn a method into a background job.

This wraps everything into a job with the DelayedClass as the job name. We should be smarter about unwrapping and naming that, rather than lumping everything into a single DelayedClass name in the UI.

Sidekiq code: https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/extensions/class_methods.rb#L13

3.0.0.pre9 installation fails on Windows

My environment is mri 2.3.3 (x86, mingw32) on Windows 10. I'm trying to upgrade from 1.6.8 to 3.0.0.pre9, but the gem install is failing.

$ gem install scout_apm -v '3.0.0.pre9'
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
ERROR:  Error installing scout_apm:
        ERROR: Failed to build gem native extension.

(...snip...)

generating allocations-i386-mingw32.def
compiling allocations.c
allocations.c:13:45: fatal error: sys/resource.h: No such file or directory
compilation terminated.
make: *** [allocations.o] Error 1

make failed, exit code 2

(...snip...)

mkmf.log doesn't have anything helpful, but it doesn't matter. The problem is sys/resource.h (and probably also sys/time.h) headers & some linux/posix specific stuff.

Now, this is just for development. It is not super critical that scoutapm be collecting allocations for my dev environment, so I think the simplest thing here is to just #ifdef _WIN32 some stuff.

I have done that here, in my fork, which solves the problem on my machine:
https://github.com/scoutapp/scout_apm_ruby/compare/v3.0.0.pre9...aharpervc:fix-windows-installation?expand=1

I'm happy to open a pr & work through your testing/ci system, but this is based off of the v3.0.0.pre9 tag which I can't seem to base a pr against. Is there a branch that tracks that work I can base it on?

gem not compiling on Alpine Linux 3.4

I am building a docker rails image based on ruby:2.4-alpine3.4.

When running bundle install --without development test the following it output. I could not find any reference that gives me a clue about what I am missing. Any help is really appreciated.

Apart than the default packages provided within the base image I am also installing:

RUN apk add --no-cache git libxml2-dev postgresql-dev build-base

output:

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/scout_apm-3.0.0.pre9/ext/stacks
/usr/local/bin/ruby -r ./siteconf20170920-20724-1i4x96b.rb extconf.rb
checking for rb_postponed_job_register_one()... yes
checking for rb_profile_frames()... yes
checking for rb_profile_frame_absolute_path()... yes
checking for rb_profile_frame_label()... yes
checking for rb_profile_frame_classpath()... yes
checking for __linux__... yes
checking for main() in -lrt... yes
checking for stdatomic.h... yes
creating Makefile

current directory: /usr/local/bundle/gems/scout_apm-3.0.0.pre9/ext/stacks
make "DESTDIR=" clean

current directory: /usr/local/bundle/gems/scout_apm-3.0.0.pre9/ext/stacks
make "DESTDIR="
compiling stacks.c
stacks.c: In function 'init_thread_vars':
stacks.c:303:23: error: 'SIGEV_THREAD_ID' undeclared (first use in this function)
   _sev.sigev_notify = SIGEV_THREAD_ID;
                       ^
stacks.c:303:23: note: each undeclared identifier is reported only once for each function it appears in
stacks.c:305:7: error: 'struct sigevent' has no member named '_sigev_un'
   _sev.sigev_notify_thread_id = syscall(SYS_gettid);
       ^
Makefile:238: recipe for target 'stacks.o' failed
make: *** [stacks.o] Error 1

make failed, exit code 2

Gem files will remain installed in /usr/local/bundle/gems/scout_apm-3.0.0.pre9 for inspection.
Results logged to /usr/local/bundle/extensions/x86_64-linux/2.3.0/scout_apm-3.0.0.pre9/gem_make.out

An error occurred while installing scout_apm (3.0.0.pre9), and Bundler cannot continue.
Make sure that `gem install scout_apm -v '3.0.0.pre9'` succeeds before bundling.

In Gemfile:
  scout_apm

Handle Webrick daemonize flag

If you start Rails with rails server -d, it starts the rails app, then does the daemonization forking. The resulting running app doesn't have the agent's background worker running, and won't ever report.

Scout APM doesn't start with "rails server"

Looks like the app servers aren't yet in the Object space when a Rails app is started locally with rails server.

Not an issue for production environments, but for folks testing things out locally first, it could be a concern.

Allow DevTrace to run on non-development environments

A few people have wanted to run DevTrace against their staging environment, or other remote environment.

Right now, we never even insert the DevTrace middleware if the rails environment isn't exactly development.

Ideally this would move to an environment variable - perhaps another flag, or set of flags to override our dev-only check, and/or add some security checks. Would have to balance the need for security and usability. Don't want to make it too easy to allow customers to accidentally expose devtrace to their customers.

Allow tracing of rake tasks

Allow the agent to run and report against individual rake tasks.

Rake tasks often get called by cron to do slow input, but are not long-running daemons the way a web server or a background job server are.

For a motivating (simplified) example:

task :import do
  data = File.read("data.txt")
  data.lines.each do |line|
    # Do work on line, with this loop in aggregate taking a fair bit of time
  end

  # Then exit when finished.
end

Ideally we'll be able to instrument however makes the most sense to the customer, either as a single "job" (the parsing of data.txt) or as a series of jobs, one after another (handling each line as a distinct job).

Grape compatibility?

I see you are beginning to support grape: https://github.com/scoutapp/scout_apm_ruby/blob/master/lib/scout_apm/instruments/grape.rb

Question, what versions of Grape do you support? We're running 0.13.0 and saw this error when we tried to upgrade to v2.0 of the scout_apm_ruby gem:

Message ArgumentError: wrong number of arguments (1 for 0)
Backtrace
grape.rb 32 run_with_scout_instruments(...)
[GEM_ROOT]/gems/scout_apm-2.0.0/lib/scout_apm/instruments/grape.rb:32:in `run_with_scout_instruments'

Too much "info" logs

Hello,

My server logs are full of "info" logs written by scout, which should be - I think - written as "debug" logs.
I don't really care what scout is "instrumenting" or "attempting".

The only logs that can be "info" are the last 2 lines or the init :

INFO : Scout Agent [2.1.32] Initialized
INFO : Sending Application Startup Info - App Server: webrick, Framework: Rails, Framework Version: 5.0.6, Database Engine: postgres

Thank you,

Damien

v3.0.0.pre9 crash (#frame_file)

Pre-release 9 version of scout apm crashed the host app.

Here's the offending line: https://github.com/scoutapp/scout_apm_ruby/blob/v3.0.0.pre9/lib/scout_apm/trace_compactor.rb#L201

And here's the stacktrace:

/rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:201: [BUG] frame2iseq: unreachable 
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux] 
-- Control frame information ----------------------------------------------- 
c:0075 p:---- s:0501 e:000500 CFUNC  :frame_file 
c:0074 p:0022 s:0496 e:000495 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:201 
c:0073 p:0033 s:0492 e:000491 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:183 
c:0072 p:0051 s:0486 e:000485 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:228 [FINISH] 
c:0071 p:---- s:0480 e:000479 CFUNC  :find_index 
c:0070 p:0013 s:0476 e:000475 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:134 
c:0069 p:0040 s:0471 e:000470 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:115 [FINISH] 
c:0068 p:---- s:0465 e:000464 CFUNC  :new 
c:0067 p:0029 s:0459 e:000458 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:64 
c:0066 p:0014 s:0453 e:000452 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/trace_compactor.rb:54 
c:0065 p:0205 s:0448 e:000446 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/converter_base.rb:190 
c:0064 p:0038 s:0436 e:000435 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/slow_request_converter.rb:72 
c:0063 p:0024 s:0432 e:000431 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/depth_first_walker.rb:28 
c:0062 p:0008 s:0428 e:000427 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_children_set.rb:56 [FINISH] 
c:0061 p:---- s:0424 e:000423 CFUNC  :each_key 
c:0060 p:0033 s:0420 e:000419 METHOD /usr/local/lib/ruby/2.4.0/set.rb:324 
c:0059 p:0010 s:0415 E:0001c0 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_children_set.rb:55 [FINISH] 
c:0058 p:---- s:0410 e:000409 CFUNC  :each 
c:0057 p:0012 s:0406 E:002080 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_children_set.rb:54 
c:0056 p:0071 s:0402 E:0024b0 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/depth_first_walker.rb:26 
c:0055 p:0040 s:0396 E:0021c0 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/slow_request_converter.rb:67 
c:0054 p:0112 s:0390 e:000389 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/layer_converters/slow_request_converter.rb:38 
c:0053 p:0039 s:0382 e:000377 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/scored_item_set.rb:81 
c:0052 p:0160 s:0373 e:000372 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/scored_item_set.rb:62 
c:0051 p:0013 s:0366 e:000365 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/store.rb:229 [FINISH] 
c:0050 p:---- s:0362 e:000361 CFUNC  :each 
c:0049 p:0014 s:0358 e:000357 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/store.rb:228 
c:0048 p:0013 s:0353 e:000352 BLOCK  /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/store.rb:60 [FINISH] 
c:0047 p:---- s:0350 e:000349 CFUNC  :synchronize 
c:0046 p:0023 s:0346 e:000345 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/store.rb:59 
c:0045 p:0276 s:0341 e:000340 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/tracked_request.rb:282 
c:0044 p:0070 s:0329 e:000328 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/tracked_request.rb:188 
c:0043 p:0188 s:0325 e:000324 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/tracked_request.rb:101 
c:0042 p:0061 s:0320 e:000318 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/instruments/rails_router.rb:25 
c:0041 p:0208 s:0313 e:000312 METHOD /rubygems/gems/omniauth-1.6.1/lib/omniauth/strategy.rb:189 
c:0040 p:0013 s:0307 e:000306 METHOD /rubygems/gems/omniauth-1.6.1/lib/omniauth/strategy.rb:167 
c:0039 p:0013 s:0302 e:000301 METHOD /rubygems/gems/omniauth-1.6.1/lib/omniauth/builder.rb:63 
c:0038 p:0042 s:0297 e:000296 METHOD /rubygems/gems/scout_apm-3.0.0.pre9/lib/scout_apm/middleware.rb:15 
c:0037 p:0140 s:0292 e:000291 METHOD /rubygems/gems/rack-attack-5.0.1/lib/rack/attack.rb:147 
c:0036 p:0095 s:0286 e:000285 METHOD /rubygems/gems/remotipart-1.3.1/lib/remotipart/middleware.rb:32 
c:0035 p:0012 s:0279 e:000278 METHOD /rubygems/gems/rack-2.0.3/lib/rack/etag.rb:25 
c:0034 p:0058 s:0268 e:000267 METHOD /rubygems/gems/rack-2.0.3/lib/rack/conditional_get.rb:25 
c:0033 p:0012 s:0259 e:000258 METHOD /rubygems/gems/rack-2.0.3/lib/rack/head.rb:12 
c:0032 p:0038 s:0251 e:000250 METHOD /rubygems/gems/rack-2.0.3/lib/rack/session/abstract/id.rb:232 
c:0031 p:0010 s:0240 e:000239 METHOD /rubygems/gems/rack-2.0.3/lib/rack/session/abstract/id.rb:226 
c:0030 p:0030 s:0235 e:000234 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/cookies.rb:613 
c:0029 p:0014 s:0225 e:000224 BLOCK  /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/callbacks.rb:26 
c:0028 p:0037 s:0222 e:000221 METHOD /rubygems/gems/activesupport-5.1.1/lib/active_support/callbacks.rb:97 
c:0027 p:0016 s:0213 e:000212 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/callbacks.rb:24 
c:0026 p:0014 s:0206 e:000205 METHOD /rubygems/gems/airbrake-6.1.1/lib/airbrake/rack/middleware.rb:52 
c:0025 p:0030 s:0198 e:000197 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/debug_exceptions.rb:59 
c:0024 p:0030 s:0187 e:000186 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/show_exceptions.rb:31 
c:0023 p:0021 s:0180 e:000179 METHOD /rubygems/gems/lograge-0.5.1/lib/lograge/rails_ext/rack/logger.rb:15 
c:0022 p:0012 s:0174 e:000173 BLOCK  /rubygems/gems/railties-5.1.1/lib/rails/rack/logger.rb:24 
c:0021 p:0007 s:0171 e:000170 BLOCK  /rubygems/gems/activesupport-5.1.1/lib/active_support/tagged_logging.rb:69 
c:0020 p:0019 s:0168 e:000167 METHOD /rubygems/gems/activesupport-5.1.1/lib/active_support/tagged_logging.rb:26 
c:0019 p:0016 s:0162 e:000161 METHOD /rubygems/gems/activesupport-5.1.1/lib/active_support/tagged_logging.rb:69 
c:0018 p:0049 s:0157 e:000156 METHOD /rubygems/gems/railties-5.1.1/lib/rails/rack/logger.rb:24 
c:0017 p:0061 s:0151 e:000150 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/remote_ip.rb:79 
c:0016 p:0047 s:0145 e:000144 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/request_id.rb:25 
c:0015 p:0105 s:0139 e:000138 METHOD /rubygems/gems/rack-2.0.3/lib/rack/method_override.rb:22 
c:0014 p:0026 s:0133 e:000132 METHOD /rubygems/gems/rack-2.0.3/lib/rack/runtime.rb:22 
c:0013 p:0024 s:0123 e:000122 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/executor.rb:12 
c:0012 p:0103 s:0115 e:000114 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/static.rb:125 
c:0011 p:0012 s:0107 e:000106 METHOD /rubygems/gems/rack-2.0.3/lib/rack/sendfile.rb:111 
c:0010 p:0037 s:0095 e:000094 METHOD /rubygems/gems/actionpack-5.1.1/lib/action_dispatch/middleware/ssl.rb:66 
c:0009 p:0053 s:0089 e:000088 METHOD /rubygems/gems/letsencrypt_rack-0.1.2/lib/letsencrypt_rack/middleware.rb:11 
c:0008 p:0030 s:0083 e:000082 METHOD /rubygems/gems/secure_headers-3.6.4/lib/secure_headers/middleware.rb:12 
c:0007 p:0026 s:0073 e:000072 METHOD /rubygems/gems/railties-5.1.1/lib/rails/engine.rb:522 
c:0006 p:0032 s:0067 e:000066 METHOD /rubygems/gems/puma-3.9.1/lib/puma/configuration.rb:224 
c:0005 p:0275 s:0062 e:000061 METHOD /rubygems/gems/puma-3.9.1/lib/puma/server.rb:602 
c:0004 p:0040 s:0037 e:000036 METHOD /rubygems/gems/puma-3.9.1/lib/puma/server.rb:435 
c:0003 p:0084 s:0025 e:000024 BLOCK  /rubygems/gems/puma-3.9.1/lib/puma/server.rb:299 [FINISH] 
c:0002 p:0161 s:0015 e:000014 BLOCK  /rubygems/gems/puma-3.9.1/lib/puma/thread_pool.rb:120 [FINISH] 
c:0001 p:---- s:0003 e:000002 (none) [FINISH]

Environment info:
ruby 2.4.1 from official Docker image, running on Heroku
web server (puma) was up for about 18 hours before crash

That crash happened so far only once (two days ago).

Is there any way I can help you debug that further?

ScoutProf-triggered SEGFAULT

A user reported a SEGFAULT when running Scout on his local development computer w/ScoutProf.

  • Backtrace
  • ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]

Two exception backtraces were sent - the first doesn't have the full backtrace, but points to the location where ScoutProf is started:

/Users/zdrummond/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/scout_apm-3.0.0.pre10/lib/scout_apm/tracked_request.rb:193: [BUG] Segmentation fault at 0x007ffdec7cd730

Error when using response streaming (ActionController::Live)

This error happened only once so far, after an action in a ActionController::Live-enabled controller finished responding.
ActionController::Live processes actions in a separate thread that has all thread-local variables copied from the parent thread.
Since Scout uses such variable to track current request and its "layers", we and up with two separate copies of that object, that apparently end up colliding? That's my guess anyway.

Here's the stack trace:

NoMethodError (undefined method `legacy_metric_name' for nil:NilClass): 
   
scout_apm (3.0.0.pre10) lib/scout_apm/layer_converters/request_queue_time_converter.rb:28:in `call' 
scout_apm (3.0.0.pre10) lib/scout_apm/tracked_request.rb:284:in `record!' 
scout_apm (3.0.0.pre10) lib/scout_apm/tracked_request.rb:188:in `stop_request' 
scout_apm (3.0.0.pre10) lib/scout_apm/tracked_request.rb:101:in `stop_layer' 
scout_apm (3.0.0.pre10) lib/scout_apm/instruments/rails_router.rb:25:in `call_with_scout_instruments' 
omniauth (1.6.1) lib/omniauth/strategy.rb:189:in `call!' 
omniauth (1.6.1) lib/omniauth/strategy.rb:167:in `call' 
omniauth (1.6.1) lib/omniauth/builder.rb:63:in `call' 
scout_apm (3.0.0.pre10) lib/scout_apm/middleware.rb:15:in `call' 
rack-attack (5.0.1) lib/rack/attack.rb:147:in `call' 
remotipart (1.3.1) lib/remotipart/middleware.rb:32:in `call' 
rack (2.0.3) lib/rack/etag.rb:25:in `call' 
rack (2.0.3) lib/rack/conditional_get.rb:38:in `call' 
rack (2.0.3) lib/rack/head.rb:12:in `call' 
rack (2.0.3) lib/rack/session/abstract/id.rb:232:in `context' 
rack (2.0.3) lib/rack/session/abstract/id.rb:226:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/cookies.rb:613:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call' 
activesupport (5.1.2) lib/active_support/callbacks.rb:97:in `run_callbacks' 
actionpack (5.1.2) lib/action_dispatch/middleware/callbacks.rb:24:in `call' 
airbrake (6.2.1) lib/airbrake/rack/middleware.rb:52:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call' 
railties (5.1.2) lib/rails/rack/logger.rb:36:in `call_app' 
railties (5.1.2) lib/rails/rack/logger.rb:24:in `block in call' 
activesupport (5.1.2) lib/active_support/tagged_logging.rb:69:in `block in tagged' 
activesupport (5.1.2) lib/active_support/tagged_logging.rb:26:in `tagged' 
activesupport (5.1.2) lib/active_support/tagged_logging.rb:69:in `tagged' 
railties (5.1.2) lib/rails/rack/logger.rb:24:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/remote_ip.rb:79:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/request_id.rb:25:in `call' 
rack (2.0.3) lib/rack/method_override.rb:22:in `call' 
rack (2.0.3) lib/rack/runtime.rb:22:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/executor.rb:12:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/static.rb:125:in `call' 
rack (2.0.3) lib/rack/sendfile.rb:111:in `call' 
actionpack (5.1.2) lib/action_dispatch/middleware/ssl.rb:66:in `call' 
letsencrypt_rack (0.1.2) lib/letsencrypt_rack/middleware.rb:11:in `call' 
secure_headers (3.6.7) lib/secure_headers/middleware.rb:12:in `call' 
railties (5.1.2) lib/rails/engine.rb:522:in `call' 
puma (3.9.1) lib/puma/configuration.rb:224:in `call' 
puma (3.9.1) lib/puma/server.rb:602:in `handle_request' 
puma (3.9.1) lib/puma/server.rb:435:in `process_client' 
puma (3.9.1) lib/puma/server.rb:299:in `block in run' 
puma (3.9.1) lib/puma/thread_pool.rb:120:in `block in spawn_thread' 

Investigate ScoutProf throttling when CPU-constrained

We've heard a couple reports of ScoutProf adding significant overhead. We'd expect this to normally be in the 5 ms range, but these report more overhead:

image

One possible factor: in the above screenshot, the CPU usage averaged 40% for the Rails processes prior to running the ScoutProf BETA. That's decent CPU usage for the Rails processes. Running ScoutProf - which consumes CPU - may tip things over, similar to the type of behavior described here.

If we think it's just a resource problem, we should discuss some ways to automatically throttle ScoutProf down (increasing the sample interval or completely turn off) if we detect the host node is swamped.

A basic, non-intelligent step: add a config option for the ScoutProf sampling interval. This could at least isolate if the sampling rate is a driver for this problem.

/cc @dlanderson @cschneid

stack-error too deep on ActiveRecord#save w/db monitoring agent

Hello!

We hit a snag deploying 2.3.0.pre to production. It looks like both gems are hooking into ActiveRecord#save in different ways and it's causing it.

  File "/app/vendor/bundle/ruby/2.4.0/gems/scout_apm-2.3.0.pre/lib/scout_apm/instruments/active_record.rb", line 266, in save_with_scout_instruments
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 15, in block in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/transaction.rb", line 859, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent.rb", line 587, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 14, in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/scout_apm-2.3.0.pre/lib/scout_apm/instruments/active_record.rb", line 266, in save_with_scout_instruments
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 15, in block in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/transaction.rb", line 859, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent.rb", line 587, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 14, in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/scout_apm-2.3.0.pre/lib/scout_apm/instruments/active_record.rb", line 266, in save_with_scout_instruments
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 15, in block in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/transaction.rb", line 859, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent.rb", line 587, in with_database_metric_name
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 14, in save
  File "/app/vendor/bundle/ruby/2.4.0/gems/scout_apm-2.3.0.pre/lib/scout_apm/instruments/active_record.rb", line 266, in save_with_scout_instruments
  File "/app/vendor/bundle/ruby/2.4.0/gems/newrelic_rpm-4.4.0.336/lib/new_relic/agent/instrumentation/active_record_5.rb", line 15, in block in save
.... many many many more lines of this same thing.

As best I can tell, this line in this commit using alias_method chaining really doesn't work well when combined with the prepending that NewRelic does.

We rolled the scout_apm back to before that commit and it's working fine again, but since we were testing out the pre I thought I'd put up a flag for this.

💕 💖

Exception: undefined method `record_stop_time!' for nil:NilClass

  • ruby 2.1.8p440 (2015-12-16 revision 53160) [x86_64-linux-gnu]
  • rails 3.2.22.1
  • scout_apm (2.0.0.pre)
App 6038 stderr: [ 2016-05-31 22:07:27.8294 6166/0x000000038fc048(Worker 12) utils.rb:71 ]: *** Exception NoMethodError in Rack application object (undefined method `record_stop_time!' for nil:NilClass) (process 6166, thread 0x000000038fc048(Worker 12)):
[ 2016-05-31 22:07:27.8295 6001/7f8d0bfff700 age/Cor/Con/InternalUtils.cpp:96 ]: [Client 3-36] Sending 502 response: application did not send a complete response
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/scout_apm-2.0.0.pre/lib/scout_apm/tracked_request.rb:70:in `stop_layer'
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/scout_apm-2.0.0.pre/lib/scout_apm/instruments/middleware_summary.rb:46:in `call'
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/railties-3.2.22.1/lib/rails/engine.rb:484:in `call'
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/railties-3.2.22.1/lib/rails/application.rb:231:in `call'
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/railties-3.2.22.1/lib/rails/railtie/configurable.rb:30:in `method_missing'
App 6038 stderr:    from /var/www/sg/vendor/cache/ruby/2.1.0/gems/newrelic_rpm-3.14.0.305/lib/new_relic/agent/instrumentation/middleware_tracing.rb:78:in `call'
App 6038 stderr:    from /usr/lib/ruby/vendor_ruby/phusion_passenger/rack/thread_handler_extension.rb:81:in `process_request'
App 6038 stderr:    from /usr/lib/ruby/vendor_ruby/phusion_passenger/request_handler/thread_handler.rb:137:in `accept_and_process_next_request'
App 6038 stderr:    from /usr/lib/ruby/vendor_ruby/phusion_passenger/request_handler/thread_handler.rb:98:in `main_loop'
App 6038 stderr:    from /usr/lib/ruby/vendor_ruby/phusion_passenger/request_handler.rb:440:in `block (3 levels) in start_threads'
App 6038 stderr:    from /usr/lib/ruby/vendor_ruby/phusion_passenger/utils.rb:97:in `block in create_thread_and_abort_on_exception'

Dev Trace not working with Rollbar js auto inject

We use the Rollbar gem and it injects javascript via middleware also. We have this turned on in development. I'm assuming it's messing with it somehow.

use ScoutApm::Middleware
use ScoutApm::Instant::Middleware
use OmniAuth::Builder
use Rollbar::Middleware::Js

This is the middleware order. Not sure if it's a problem with Rollbar gem or just the order of the middleware. Just letting you guys know. We should probably just stub Rollbar for development and this wouldn't be a problem.

Thanks.

Rails API only mode automatic support

Currently Scout includes instruments on ActionController::Base, and having your app controllers inherit from anything else (like ActionController::Metal or ActionController::API) requires manually including instruments. Rails 5 when run in API only mode has a config option set inside application.rb: config.api_only = true. It would be awesome to check this configuration at runtime and include instruments in ActionController::API as well!

Broken Tests in Ruby 1.8.7

I fixed some issues in #17. These are remaining broken tests:

  1) Failure:
PayloadSerializerTest#test_serializes_metrics_as_json [./test/unit/serializers/payload_serializer_test.rb:113]:
--- expected
+++ actual
@@ -1 +1 @@
-[{"total_call_time"=>0.033245704, "total_exclusive_time"=>0.033245704, "call_count"=>16, "min_call_time"=>0.000613518, "max_call_time"=>0.005338062, "key"=>{"scope"=>{"name"=>"apps/checkin", "bucket"=>"Controller"}, "desc"=>"SELECT * from users where filter=?", "name"=>"all", "bucket"=>"ActiveRecord", "extra"=>{"user"=>"cooluser"}}}, {"total_call_time"=>0.113403176, "total_exclusive_time"=>0.078132089, "call_count"=>2, "min_call_time"=>0.034881757, "max_call_time"=>0.078521419, "key"=>{"scope"=>nil, "desc"=>nil, "name"=>"apps/checkin", "bucket"=>"Controller", "extra"=>{}}}]
+[{"total_call_time"=>0.113403176, "total_exclusive_time"=>0.078132089, "call_count"=>2, "max_call_time"=>0.078521419, "min_call_time"=>0.034881757, "key"=>{"desc"=>nil, "scope"=>nil, "name"=>"apps/checkin", "bucket"=>"Controller", "extra"=>{}}}, {"total_call_time"=>0.033245704, "total_exclusive_time"=>0.033245704, "call_count"=>16, "max_call_time"=>0.005338062, "min_call_time"=>0.000613518, "key"=>{"desc"=>"SELECT * from users where filter=?", "scope"=>{"name"=>"apps/checkin", "bucket"=>"Controller"}, "name"=>"all", "bucket"=>"ActiveRecord", "extra"=>{"user"=>"cooluser"}}}]



  2) Failure:
PayloadSerializerTest#test_serializes_slow_transactions_as_json [./test/unit/serializers/payload_serializer_test.rb:198]:
--- expected
+++ actual
@@ -1 +1 @@
-[{"context"=>{"user"=>{"hello"=>"goodbye"}, "this"=>"that"}, "metrics"=>[{"total_call_time"=>0.033245704, "total_exclusive_time"=>0.033245704, "call_count"=>16, "min_call_time"=>0.000613518, "max_call_time"=>0.005338062, "key"=>{"scope"=>{"name"=>"apps/checkin", "bucket"=>"Controller"}, "desc"=>"SELECT * from users where filter=?", "name"=>"all", "bucket"=>"ActiveRecord", "extra"=>{"user"=>"cooluser"}}}, {"total_call_time"=>0.113403176, "total_exclusive_time"=>0.078132089, "call_count"=>2, "min_call_time"=>0.034881757, "max_call_time"=>0.078521419, "key"=>{"scope"=>nil, "desc"=>nil, "name"=>"apps/checkin", "bucket"=>"Controller", "extra"=>{}}}], "total_call_time"=>1.23, "uri"=>"http://example.com/blabla", "time"=>"2015-11-22 06:26:28 -0700", "prof"=>[], "key"=>{"name"=>"something/else", "bucket"=>"Buckethead"}}]
+[{"context"=>{"user"=>{"hello"=>"goodbye"}, "this"=>"that"}, "metrics"=>[{"total_call_time"=>0.113403176, "total_exclusive_time"=>0.078132089, "call_count"=>2, "max_call_time"=>0.078521419, "min_call_time"=>0.034881757, "key"=>{"desc"=>nil, "scope"=>nil, "name"=>"apps/checkin", "bucket"=>"Controller", "extra"=>{}}}, {"total_call_time"=>0.033245704, "total_exclusive_time"=>0.033245704, "call_count"=>16, "max_call_time"=>0.005338062, "min_call_time"=>0.000613518, "key"=>{"desc"=>"SELECT * from users where filter=?", "scope"=>{"name"=>"apps/checkin", "bucket"=>"Controller"}, "name"=>"all", "bucket"=>"ActiveRecord", "extra"=>{"user"=>"cooluser"}}}], "total_call_time"=>1.23, "time"=>"Sun Nov 22 06:26:28 -0700 2015", "uri"=>"http://example.com/blabla", "prof"=>[], "key"=>{"name"=>"something/else", "bucket"=>"Buckethead"}}]



  3) Failure:
ScoutApm::Utils::SqlSanitizerTest#test_postgres_simple_select_of_first [./test/unit/sql_sanitizer_test.rb:21]:
--- expected
+++ actual
@@ -1 +1 @@
-"SELECT \"users\".* FROM \"users\" ORDER BY \"users\".\"id\" ASC LIMIT 1"
+"SELECT \"users\".* FROM \"users\" ORDER BY \"users\".\"id\" ASC LIMIT ?"



  4) Failure:
ScoutApm::Utils::SqlSanitizerTest#test_mysql_limit [./test/unit/sql_sanitizer_test.rb:57]:
--- expected
+++ actual
@@ -1 +1 @@
-"SELECT  `blogs`.* FROM `blogs`  ORDER BY `blogs`.`id` ASC LIMIT 1"
+"SELECT  `blogs`.* FROM `blogs`  ORDER BY `blogs`.`id` ASC LIMIT ?"



  5) Error:
ScoutApm::Utils::SqlSanitizerTest#test_scrubs_invalid_encoding:
NoMethodError: undefined method `force_encoding' for "SELECT `blogs`.* FROM `blogs` WHERE (title = 'a\255c')":String
    ./test/unit/sql_sanitizer_test.rb:71:in `test_scrubs_invalid_encoding'

undefined method `has_key?'

I got this error after installing

undefined method `has_key?' for nil:NilClass (NoMethodError)
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/config.rb:122:in `has_key?'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/config.rb:58:in `block in value'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/config.rb:57:in `each'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/config.rb:57:in `value'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/environment.rb:106:in `hostname'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/agent/logging.rb:31:in `format_message'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/logger.rb:434:in `add'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/logger.rb:507:in `error'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/agent/logging.rb:22:in `rescue in init_logger'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/agent/logging.rb:15:in `init_logger'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm/agent.rb:115:in `start'
  ...../gems/ruby-2.3.1/gems/scout_apm-2.0.0.pre5/lib/scout_apm.rb:154:in `block in <class:Railtie>'
  ...../gems/ruby-2.3.1/gems/railties-5.0.0/lib/rails/initializable.rb:30:in `instance_exec'
  ...../gems/ruby-2.3.1/gems/railties-5.0.0/lib/rails/initializable.rb:30:in `run'
  ...../gems/ruby-2.3.1/gems/railties-5.0.0/lib/rails/initializable.rb:55:in `block in run_initializers'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `call'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
  ...../rubies/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
  ...../gems/ruby-2.3.1/gems/railties-5.0.0/lib/rails/initializable.rb:54:in `run_initializers'
  ...../gems/ruby-2.3.1/gems/railties-5.0.0/lib/rails/application.rb:352:in `initialize!'
  ...../app/config/environment.rb:5:in `<top (required)>'
  config.ru:3:in `require'
  config.ru:3:in `block in <main>'
  ...../gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/builder.rb:55:in `instance_eval'
  ...../gems/ruby-2.3.1/gems/rack-2.0.1/lib/rack/builder.rb:55:in `initialize'
  config.ru:1:in `new'
  config.ru:1:in `<main>'
  ...../gems/ruby-2.3.1/gems/passenger-5.0.29/src/helper-scripts/rack-preloader.rb:110:in `eval'
  ...../gems/ruby-2.3.1/gems/passenger-5.0.29/src/helper-scripts/rack-preloader.rb:110:in `preload_app'
  ...../gems/ruby-2.3.1/gems/passenger-5.0.29/src/helper-scripts/rack-preloader.rb:156:in `<module:App>'
  ...../gems/ruby-2.3.1/gems/passenger-5.0.29/src/helper-scripts/rack-preloader.rb:30:in `<module:PhusionPassenger>'
  ...../gems/ruby-2.3.1/gems/passenger-5.0.29/src/helper-scripts/rack-preloader.rb:29:in `<main>'

Looking for a way to avoid `start`ing

My app has 18 deployments (6x "dev", 6x "staging", 6x "production").

We're just testing Scout on one of these ("dev-sg").

However, we get debug messages on every deployment.

$ heroku run rails c --app other_server
Running rails c on ⬢ other_server... up, run.3306 (Hobby)
[Scout] [02/19/17 01:23:07 +0000 run.3306 (4)] INFO : Attempting to start Scout Agent [2.1.22] on [run.3306]
[Scout] [02/19/17 01:23:07 +0000 run.3306 (4)] WARN : Monitoring isn't enabled for the [production] environment. Not starting agent
Loading production environment (Rails 5.0.1)
[1] pry(main)> ScoutApm::Agent.instance.apm_enabled?
=> false
[2] pry(main)> ScoutApm::Agent.instance.started?
=> false
[3] pry(main)> ScoutApm::Agent.instance.background_worker_running?
=> nil

This happens because no matter whether apm_enabled? is true or not
the Railtie tries to run ScoutApm::Agent.instance.start, which always emits these messages

https://github.com/scoutapp/scout_apm_ruby/blob/c6592a0/lib/scout_apm.rb#L156

Is there a nice way to avoid these warnings from being emitted?
From what I can see it's unavoidable right now.

JRuby Support

Currently, the scout_apm gem does not install on JRuby, since it references C extensions.

We have 2 C extensions in the mainline gem right now (and ScoutProf in the 3.x branch uses a C ext as well).

Both of the C extensions are related to memory usage:

  • Allocations - hooks to count allocations over a time frame.
  • Rusage - a vendored version of a tiny C ext for determining memory usage of the process.

Both of these are easily stubbed to return 0s, allowing the rest of the agent to work as normal. In addition, it's likely that Java contains APIs to get similar data out of the VM.

The big issue is that there doesn't seem to be any way to mark a C extension as optional for the gem. Ideally, we'd say: "do your best to build this C ext, but if not, the gem will continue to work w/ fallback code", but that doesn't seem to exist.

Other gems (like concurrent-ruby) ship an additional C ext gem (concurrent-ruby-ext). So the base gem is pure ruby, then a layered on version with C exts. This approach is a bit awkward for us, since we want our install process to be as simple and error-resistant as possible. Asking for 2 distinct gems to be installed will inevitably cause issues.

Brainstorming Approaches:

  • scout_apm_ruby is a gem with C ext, but not most of the agent code, it could reference the bulk of the agent code in a new scout_apm_ruby_core. Jruby support would be referencing the_core library directly, or perhaps a new _jruby build with custom JVM-specific support.
  • scout_apm_ruby could have a branch on github, tracking the mainline code but removing C extensions. Unsure if we'd release it directly, or just have it available in git for users to point bundler at.
  • Find a way to optionally build the C exts
  • A fancier build script which releases the normal gem, then applies JRuby patches to the code automatically and releases a _jruby version of the gem with the same version number.

Fix compilation issue with Windows / MSYS

MSYS doesn't support the posix sys/resource.h header, and hence fails to compile.

We should have some sort of fallback if that header isn't available.

Temporarily enhancing PATH for MSYS/MINGW...
Building native extensions.  This could take a while...
ERROR:  Error installing scout_apm:
        ERROR: Failed to build gem native extension.
    current directory: C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/scout_apm-2.1.26/ext/allocations
C:/Ruby24-x64/bin/ruby.exe -r ./siteconf20170719-15944-1n0ro3h.rb extconf.rb
checking for ruby/ruby.h... yes
creating Makefile
current directory: C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/scout_apm-2.1.26/ext/allocations
make "DESTDIR=" clean
current directory: C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/scout_apm-2.1.26/ext/allocations
make "DESTDIR="
generating allocations-x64-mingw32.def
compiling allocations.c
allocations.c:13:10: fatal error: sys/resource.h: No such file or directory
 #include <sys/resource.h> // is this needed?
          ^~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:242: allocations.o] Error 1
make failed, exit code 2
Gem files will remain installed in C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/scout_apm-2.1.26 for inspection.
Results logged to C:/Ruby24-x64/lib/ruby/gems/2.4.0/extensions/x64-mingw32/2.4.0/scout_apm-2.1.26/gem_make.out

Using DevTrace in a webpack application

Reading over the source of Scout Instant, I can see that for XMLHttpRequest requests, your middleware grabs the X-scoutapminstant header from the response body of the request and passes it to the ScoutInstant instance on the window object. I'm running an API instance separately to a webpack based React app, and would love to be able to get the DevTrace profiler to display on my frontend. Is there a way to proxy DevTrace or by any other means inject it into my frontend application so that I can profile requests to my API (both apps are running in Docker)

Setting SCOUT_DATA_FILE config breaks ScoutApm reporting

When the data_file config setting is set, ScoutApm agent cannot report because there's a bug in Layaway directory initialization:

/srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/layaway.rb:34:in `directory?': wrong number of arguments (0 for 1) (ArgumentError)
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/layaway.rb:34:in `directory'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/layaway.rb:125:in `glob_pattern'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/layaway.rb:112:in `file_for'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/layaway.rb:48:in `write_reporting_period'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/store.rb:74:in `block (2 levels) in write_to_layaway'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/store.rb:72:in `each'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/store.rb:72:in `block in write_to_layaway'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/store.rb:70:in `synchronize'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/store.rb:70:in `write_to_layaway'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/agent.rb:205:in `shutdown'
    from /srv/homebase/current/vendor/bundle/ruby/2.1.0/gems/scout_apm-2.0.0/lib/scout_apm/agent.rb:189:in `block in install_exit_handler'

I tried fixing this to submit a PR, but couldn't get past a series of issues when bootstrapping the project and running tests. Couple issues I ran into there:

  1. LoadError: cannot load such file -- scout_apm/utils/fake_stack_prof. There's no file matching this in the repo right now.
  2. Many undefined variables and methods, including (just two out of many):
NameError: undefined local variable or method `agent' for #<SlowRequestPolicyTest:0x007f8a4d1fd068>
    /Users/evan/Code/cotap/scout_apm_ruby/test/unit/slow_request_policy_test.rb:35:in `test_score'

and

NoMethodError: undefined method `add_reporting_period' for #<ScoutApm::Layaway:0x007f8a4e073890 @directory=nil>
    /Users/evan/Code/cotap/scout_apm_ruby/test/unit/layaway_test.rb:22:in `test_merge_reporting_period'

What am I missing? Tips on getting the tests in master passing?

DevTrace appears to conflict with RequireJS

I haven't done much investigation of this yet, but it appears like RequireJS and DevTrace conflict, causing RequireJS to break, and not load the user's frontend app.

A screenshot of the error in the dev console:

image

Boot with no warnings

Trying to eliminate all the warnings on my app codetriage.com on boot.

Originally I was getting warnings about adding a scout_apm.yml I added one even though I don't need it because i'm using the environment variable in production. I expected the warning to go away, instead I am left with a warning message:

$ rails c
I, [2016-06-22T16:48:34.372894 #7190]  INFO -- : Loaded Configuration: /Users/richardschneeman/Documents/projects/codetriage/config/scout_apm.yml. Using environment: development
Loading development environment (Rails 5.0.0.rc2)
irb(main):001:0> exit

It looks like there's no way to avoid this warning message. Could we add one? Maybe

defaults: &defaults
  name: codetriage
  key: <%= ENV['SCOUT_KEY'] %>
  monitor: <%= true if ENV['SCOUT_MONITOR'] %>
  warn_on_boot: false

ActionDispatch::RemoteIp::IpSpoofAttackError

Looks like the gem raises when attempting to access remote_ip: from gems/scout_apm-1.5.0/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb:64:inprocess_action'`

req = ScoutApm::RequestManager.lookup
path = ScoutApm::Agent.instance.config.value("uri_reporting") == 'path' ? request.path : request.fullpath
req.annotate_request(:uri => path)
req.context.add_user(:ip => request.remote_ip) # :boom:
req.set_headers(request.headers)
req.web!

I removed the IPs in the error message, but I think the important bit is that they don't match.

In my own app, with another gem, I rescued with the empty string. Perhaps that, or some identifier (e.g. SPOOFED_IP) or some such would make sense?

gems/actionpack-4.2.5.2/lib/action_dispatch/middleware/remote_ip.rb:125:in `calculate_ip': IP spoofing attack?! HTTP_CLIENT_IP="<redacted>" HTTP_X_FORWARDED_FOR="<redacted>" (ActionDispatch::RemoteIp::IpSpoofAttackError)
    from gems/actionpack-4.2.5.2/lib/action_dispatch/middleware/remote_ip.rb:144:in `to_s'
    from gems/actionpack-4.2.5.2/lib/action_dispatch/http/request.rb:231:in `remote_ip'
    from gems/scout_apm-1.5.0/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb:64:in `process_action'
    from gems/actionpack-4.2.5.2/lib/abstract_controller/base.rb:137:in `process'
    ... tons of rails middleware stack traces removed

Sequel support

Maybe we can examine queries executed by Sequel? RackMini supports Sequel and easily handle it. Maybe you can see the source code and adapt to ScoutApp?

After I GoLive, In production, I would like and love to see how much costs on Sequel operations by using Scout. Otherwise, I just not gonna see it and do not know how much time spent or which query is slow by looking to, ehrm, nothing.

Isn't working with mongoid

Hi, I'm trying to use the scout to monitor my rails app, but when beginning to track pops up a follow error:

NoMethodError: undefined method `filter' for #<Mongo::Collection::View:0x007f6c315731c8>

backtrace:
(eval):8 in first_with_scout_instruments
vendor/bundle/ruby/2.2.0/gems/mongoid-5.0.0/lib/mongoid/contextual.rb:20 in first
vendor/bundle/ruby/2.2.0/gems/orm_adapter-0.5.0/lib/orm_adapter/adapters/mongoid.rb:22 in get
vendor/bundle/ruby/2.2.0/gems/devise-3.5.2/lib/devise/models/authenticatable.rb:208 in serialize_from_session
vendor/bundle/ruby/2.2.0/gems/devise-3.5.2/lib/devise.rb:455 in block (2 levels) in configure_warden!
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/session_serializer.rb:34 in fetch
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/proxy.rb:212 in user
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/proxy.rb:318 in _perform_authentication
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/proxy.rb:104 in authenticate
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/proxy.rb:114 in authenticate?
vendor/bundle/ruby/2.2.0/gems/devise-3.5.2/app/controllers/devise_controller.rb:103 in require_no_authentication
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:432 in block in make_lambda
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:145 in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:145 in block in halting_and_conditional
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:504 in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:504 in block in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:504 in each
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:504 in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:92 in __run_callbacks__
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:778 in _run_process_action_callbacks
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:81 in run_callbacks
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/abstract_controller/callbacks.rb:19 in process_action
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal/rescue.rb:29 in process_action
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal/instrumentation.rb:32 in block in process_action
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in block in instrument
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/notifications/instrumenter.rb:20 in instrument
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164 in instrument
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal/instrumentation.rb:30 in process_action
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal/params_wrapper.rb:250 in process_action
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb:79 in process_action
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/abstract_controller/base.rb:137 in process
vendor/bundle/ruby/2.2.0/gems/actionview-4.2.4/lib/action_view/rendering.rb:30 in process
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal.rb:196 in dispatch
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal/rack_delegation.rb:13 in dispatch
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_controller/metal.rb:237 in block in action
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/routing/route_set.rb:76 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/routing/route_set.rb:76 in dispatch
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/routing/route_set.rb:45 in serve
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/routing/mapper.rb:49 in serve
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/journey/router.rb:43 in block in serve
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/journey/router.rb:30 in each
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/journey/router.rb:30 in serve
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/routing/route_set.rb:821 in call
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/instruments/rails_router.rb:23 in call_with_scout_instruments
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/middleware.rb:15 in call
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/manager.rb:35 in block in call
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/manager.rb:34 in catch
vendor/bundle/ruby/2.2.0/gems/warden-1.2.3/lib/warden/manager.rb:34 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/etag.rb:24 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/conditionalget.rb:25 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/head.rb:13 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/params_parser.rb:27 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/flash.rb:260 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:225 in context
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:220 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/cookies.rb:560 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/callbacks.rb:29 in block in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:88 in __run_callbacks__
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:778 in _run_call_callbacks
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:81 in run_callbacks
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/callbacks.rb:27 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/remote_ip.rb:78 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/debug_exceptions.rb:17 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/show_exceptions.rb:30 in call
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/rack/logger.rb:38 in call_app
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/rack/logger.rb:20 in block in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:68 in block in tagged
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:26 in tagged
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/tagged_logging.rb:68 in tagged
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/rack/logger.rb:20 in call
vendor/bundle/ruby/2.2.0/gems/request_store-1.2.0/lib/request_store/middleware.rb:8 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/request_id.rb:21 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/methodoverride.rb:22 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/runtime.rb:18 in call
vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/cache/strategy/local_cache_middleware.rb:28 in call
vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.4/lib/action_dispatch/middleware/static.rb:116 in call
vendor/bundle/ruby/2.2.0/gems/font_assets-0.1.11/lib/font_assets/middleware.rb:29 in call
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/sendfile.rb:113 in call
vendor/bundle/ruby/2.2.0/gems/rack-cors-0.4.0/lib/rack/cors.rb:80 in call
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/instruments/middleware_summary.rb:52 in call
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:518 in call
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:165 in call
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/railtie.rb:194 in public_send
vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/railtie.rb:194 in method_missing
vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/deflater.rb:35 in call
vendor/bundle/ruby/2.2.0/gems/unicorn-4.9.0/lib/unicorn/http_server.rb:580 in process_client
vendor/bundle/ruby/2.2.0/gems/unicorn-4.9.0/lib/unicorn/http_server.rb:674 in worker_loop
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/server_integrations/unicorn.rb:52 in call
vendor/bundle/ruby/2.2.0/gems/scout_apm-2.1.8/lib/scout_apm/server_integrations/unicorn.rb:52 in block (2 levels) in install
vendor/bundle/ruby/2.2.0/gems/unicorn-4.9.0/lib/unicorn/http_server.rb:529 in spawn_missing_workers
vendor/bundle/ruby/2.2.0/gems/unicorn-4.9.0/lib/unicorn/http_server.rb:140 in start
vendor/bundle/ruby/2.2.0/gems/unicorn-4.9.0/bin/unicorn:126 in <top (required)>
vendor/bundle/ruby/2.2.0/bin/unicorn:23 in load
vendor/bundle/ruby/2.2.0/bin/unicorn:23 in <main>

The app is using ruby 2.2.2, rails 4.2.4 and mongoid 5.0.0, I'm not sure if there is any additional configuration beyond to install scout_apm gem.

Any ideas how to resolve this trouble?

DevTrace should be easy to inject manually

Many people who use Single Page Apps (react / angular / ember) serve static html as their initial load, and don't go through the Rails middleware.

Since it doesn't go through middleware, the DevTrace javascript doesn't get injected.

We should make sure the DevTrace javascript can be included directly via a script tag into a user's non-rails HTML, and start reading XHR requests made to an instrumented Rails application.

DevTrace and Turbolinks

Hey guys,

Superb job on Scout and DevTrace. One snag I found is that DevTrace doesn't play well with Turbolinks (tested on a Rails 5.1 app). Because of the way turbolinks works (effectively merging the head and replacing the body on the fly on new requests), the devtrace widget cannot be found after the first request.

Uncaught TypeError: Cannot read property 'unique_id' of undefined
    at expandedProfileToHTML (scout_instant.js?cachebust=1496923205:224)
    at ub.<anonymous> (scout_instant.js?cachebust=1496923205:161)
    at p (scout_instant.js?cachebust=1496922257:4)
    at ub.each (scout_instant.js?cachebust=1496922257:4)
    at renderMessages (scout_instant.js?cachebust=1496923205:155)
    at initialize (scout_instant.js?cachebust=1496923205:95)

I have debugged this situation with other pieces of software before (namely Zendesk) and it usually requires a bit of refactoring so that the widget rebuilds itself on a turbolinks:load event (their documentation on that is available here).

Happy to provide further information on what's happening, if I'm able.

Truncate vs. Drop Large SQL Statements

SQLSanitizer#scrubbed drops queries that exceed 1000 chars (code). These can frequently be slow queries (more complex queries are frequently more expensive). Rather than dropping these, how about:

If length > 1000, append "..." to a 1000-length truncated string

The "..." should appear in our sanitized query so the UI makes it clear the query was truncated.

I think it is more involved than just str[0..999] on L78. We probably only want to do this if the string is encoded properly and isn't binary.

SIGALRM crash with ::API controllers

We've had 4 reports of the BETA ScoutProf agent crashing with a SIGALRM error under the following conditions:

  • The app has controllers that inherit from ActionController::API vs. ActionController::Base and our instrumentation is manually included via our help docs.
  • ScoutProf is enabled
  • In at least two cases, the app is running inside a Docker container (either tests, Circle CI)
  • It's been observed w/Rails 4 and 5 and Ruby 2.3 and Ruby 2.2

@cschneid has tried to reproduce locally with a Rails 5 app w/o success.

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.