Giter Site home page Giter Site logo

appsignal / appsignal-nodejs Goto Github PK

View Code? Open in Web Editor NEW
29.0 5.0 9.0 13.36 MB

๐ŸŸฉ AppSignal for Node.js

Home Page: https://www.appsignal.com/nodejs/

License: MIT License

JavaScript 8.95% TypeScript 66.95% Python 0.23% C++ 5.41% Ruby 13.81% Shell 2.92% Dockerfile 0.97% CSS 0.75%
javascript nodejs performance-monitoring appsignal error-monitoring apm

appsignal-nodejs's Introduction

AppSignal apm for Ruby

AppSignal solves all your Ruby monitoring needs in a single tool. You and your team can focus on writing code and we'll provide the alerts if your app has any issues.

Build status Gem Version Code Climate

Description

The AppSignal gem collects exceptions and performance data from your Ruby applications and sends it to AppSignal for analysis. Get alerted when an error occurs or an endpoint is responding very slowly.

AppSignal aims to provide a one stop solution to all your monitoring needs. Track metrics from your servers with our Host metrics and graph everything else with our Custom metrics feature.

Usage

First make sure you've installed AppSignal in your application by following the steps in Installation.

AppSignal will automatically monitor requests, report any exceptions that are thrown and any performance issues that might have occurred.

You can also add extra information to requests by adding custom instrumentation and by adding tags.

Track any error

Catch any error and report it to AppSignal, even if it doesn't crash a request.

begin
  config = File.read("config.yml")
rescue => e
  Appsignal.set_error(e)
  # Load alternative config
  config = { :name => ENV["NAME"] }
end

Read more about Exception handling in our documentation.

Tagging

Need more information with errors and performance issues? Add tags to your requests to identify common factors for problems.

Appsignal.tag_request(
  user: current_user.id,
  locale: I18n.locale
)

Read more about Tagging in our documentation.

Custom instrumentation

If you need more fine-grained instrumentation you can add custom instrumentation anywhere in your code.

# Simple instrumentation
Appsignal.instrument("array_to_hash.expensive_logic", "Complex calculations") do
  array = [["a", 1], ["b", 2], ["c", 3]]
  Hash[array]
end

# Add the query that you're monitoring
sql = "SELECT * FROM posts ORDER BY created_at DESC LIMIT 1"
Appsignal.instrument("fetch.custom_database", "Fetch latest post", sql) do
  # ...
end

# Nested instrumentation calls are also supported!
Appsignal.instrument("fetch.custom_database", "Fetch current user") do
  # ...

  Appsignal.instrument("write.custom_database", "Write user update") do
    # ...
  end
end

Read more about custom instrumentation in our documentation.

Installation

First, sign up for an AppSignal account and add the appsignal gem to your Gemfile. Then, run bundle install.

# Gemfile
gem "appsignal"

Afterward, you can use the appsignal install command to install AppSignal into your application by using the "Push API key". This will guide you through our installation wizard.

appsignal install [push api key]

Depending on what framework or gems you use some manual integration is required. Follow the steps in the wizard or consult our integrations page for help.

If you're stuck feel free to contact us!

Supported frameworks and gems

AppSignal automatically supports a collection of Ruby frameworks and gems, including but not limited to:

  • Ruby on Rails
  • Rack
  • Sinatra
  • Padrino
  • Grape
  • Webmachine
  • Capistrano
  • Sidekiq
  • Delayed Job
  • Resque
  • Rake

AppSignal instrumentation doesn't depend on automatic integrations. It's easy to set up custom instrumentation to add keep track of anything.

For more detailed information and examples please visit our integrations page.

Front-end monitoring (Beta)

We have a Front-end monitoring program running in Beta currently. Be sure to check it out!

Supported systems

Currently the AppSignal agent works on most Unix-like operating systems, such as most Linux distributions, FreeBSD, macOS, excluding Microsoft Windows.

For more detailed information please visit our Supported systems page.

Releases

Following the process below to release a new version of the Ruby gem.

  1. Make sure mono is installed by following the installation instructions.
  2. Run: mono publish
    • Mono will automatically bump the version number based on the .changesets/.
    • Mono will automatically update the CHANGELOG.md file based on the .changesets/.
  3. Confirm with your two-factor authentication token for Rubygems.org, twice.

Development

Installation

Make sure you have Bundler installed and then use the Rake install task to install all possible dependencies.

# Install Bundler
gem install bundler
# Bootstrap the project
mono bootstrap
# Install the AppSignal extension and _all_ gems we support.
bundle exec rake install
# Only install the AppSignal extension.
bundle exec rake extension:install

Git source for Bundler

When specifying a git source for the AppSignal gem in Bundler we do not support JRuby. This is because our gemspec defaults to the Ruby implementation for installing the AppSignal C-extension.

# Gemfile
gem "appsignal",
  :git => "https://github.com/appsignal/appsignal-ruby.git",
  :branch => "main"

When you need to use a git source of the gem in your JRuby install, you'll need to run the following to install the C-extension on JRuby. Note that this post-install step is not possible on platforms such as Heroku where the app is sent through a deploy pipeline and the app is started immediately after.

bundle install
(cd $(bundle show appsignal)/ext && rake)

Testing

bundle exec rspec
# Or with one file
bundle exec rspec spec/lib/appsignal_spec.rb

Note that some specs depend on certain other gems to run and if they are not loaded RSpec will not run them. See also Testing with other gems.

Testing with other gems

AppSignal runs in many different configurations. To replicate these configurations you need to run the spec suite with a specific Gemfile.

BUNDLE_GEMFILE=gemfiles/capistrano2.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/capistrano3.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/dry-monitor.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/grape.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/hanami.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/http5.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/no_dependencies.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/padrino.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/que.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/que_beta.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-3.2.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-4.0.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-4.1.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-5.0.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-5.1.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-5.2.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/rails-6.0.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/resque-1.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/resque-2.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/sequel-435.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/sequel.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/sinatra.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/webmachine.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/redis-4.gemfile bundle exec rspec
BUNDLE_GEMFILE=gemfiles/redis-5.gemfile bundle exec rspec

If you have either RVM, rbenv or chruby installed you can also use rake build_matrix:local:generate to generate a script that runs specs for all Ruby versions and gem combinations we support.

We run the suite against all of the Gemfiles mentioned above and on a number of different Ruby versions.

Versioning

This gem uses Semantic Versioning.

The main branch corresponds to the current stable release of the gem.

The develop branch is used for development of features that will end up in the next minor release.

Open a Pull Request on the main branch if you're fixing a bug. For new new features, open a Pull Request on the develop branch.

Every stable and unstable release is tagged in git with a version tag.

Contributing

Thinking of contributing to our gem? Awesome! ๐Ÿš€

Please follow our Contributing guide in our documentation and follow our Code of Conduct.

Also, we would be very happy to send you Stroopwafles. Have look at everyone we send a package to so far on our Stroopwafles page.

Support

Contact us and speak directly with the engineers working on AppSignal. They will help you get set up, tweak your code and make sure you get the most out of using AppSignal.

Also see our SUPPORT.md file.

appsignal-nodejs's People

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

Watchers

 avatar  avatar  avatar  avatar  avatar

appsignal-nodejs's Issues

Remove further references to yarn

As mentioned in #32, there are several hardcoded references to yarn which will fail if the user doesn't have it installed. These should be made more generic to cover both npm and yarn.

Generic HTTP/HTTPS instrumentation

Related to #21. We'll need to leverage our module instrumentation abstraction (buzzwords!) to instrument the core Node.js HTTP/HTTPS module.

The point of this would be mainly to create and close the top-most Span for the current context (could be a RootSpan in a single machine trace, could be a ChildSpan in a multi machine trace) when an HTTP request is started and finish.

This will effectively allow us to integrate at a low-level and offer some out-of-the-box compatibility for all the major HTTP frameworks. I assume there will still be some logic that is framework specific for other tasks, and we can keep that logic in specific packages (e.g. @appsignal/express for express).

TODO:

  • HTTP Incoming Requests (#48)
  • HTTP Outgoing Requests
  • HTTPS Incoming Requests
  • HTTPS Outgoing Requests
  • HTTP2 Incoming Requests
  • HTTP2 Outgoing Requests

Port extension code to Rust

Long term, it'd be nice to port the code in appsignal_extension.cpp to Rust to keep it consistent with the rest of the agent. No doubt we could use the additional memory safety here also.

Neon would de a good option to enable this. Currently, however, N-API support is still in the early stages (we rely on N-API exclusively to interface Node with the agent).

An important part of the problem here is what happens when rustc is not installed. In Heroku boxes, for example, rustcisn't installed in the default buildpack, so people installing the agent will be unable to compile the extension.

Diagnose function

This was skipped in the initial implementation as the integration as the log output would always output an error even though the agent had started successfully.

Allow to pass environment to Appsignal contructor

Example:

const appsignal = new Appsignal({
  active: true,
  name: "<YOUR APPLICATION NAME>",
  apiKey: "<YOUR API KEY>",
  environment: "production"
})

While environment variables are great, there should always be a way to pass an arbitrary value via the contructor.

Failed to boot agent: bad path

Hello again!

The latest version of this package fails to boot the AppSignal agent with:

[2020-04-13T09:06:32 (extension) #6][Error] Failed to boot agent at '/usr/app/node_modules/@appsignal/nodejs/node_modules/@appsignal/nodejs-ext/ext/appsignal-agent': No such file or directory (os error 2)

The agent binary is actually in /usr/app/node_modules/@appsignal/nodejs-ext/ext/appsignal-agent.

I believe this path discovery is implemented in the proprietary extension's binary, for which we don't have access to the source code. There also seems to be a private environment variable _APPSIGNAL_AGENT_PATH that would let us override this, however the package doesn't pass it (doesn't support it).

The package was installed with

npm --version
6.14.4
node --version
v12.16.2

As the paths may differ between nodejs versions - older NPM versions do not flatten the package tree, AFAIK

Logging interface

By default, this should log to console.log in development and/or a file in production. There should also be a way to pass in a popular logging framework (winston, bunyan) and send our log messages there.

Generic module patching

In order to monkeypatch Node.js modules at runtime for instrumentation, we will need to write an abstraction that basically hijacks the module loading (require) process. See this post for more info.

Modules are kept in a "require cache" after the first require call. We will need to catch the module we'd like to instrument (for example, ioredis) when it is required, and then apply monkeypatched to the module before it is placed in the require cache.

There are two approaches AFAICT:

  • Using an abstraction that provides a safe interface for monkeypatching modules, e.g shimmer. A safe, but long winded, option.
  • Wrapping modules in Proxies. Offers a new and shiny way to do things but I'm not sure about the drawbacks currently.

Ignore webpack-hot-middleware

When using an environment that uses webpack-hot-middleware to enable hot-reloading (e.g. Next.js) in development mode, we report extremely long spans ranging from 30-60 secs in length. This is caused by the long running request opened between the browser and the hot reloader to make webpack-hot-middleware work. We'll need to ignore these to enable #100 and possibly #114.

Ignore asset paths in http instrumentation

Because we instrument http directly, any URL that is accessed currently (included static assets) is reported to AppSignal. We should ignore any static asset paths by default.

Must be closed before #100 can be closed.

Use ECMAScript private fields

During development, a new version of TypeScript was released that enables support for ECMAScript private fields. In the past, we have used the non-standard _ prefix to denote a private field. We can now switch to using the standardised version.

Depfu Error: No dependency files found

Hello,

We've tried to activate or update your repository on Depfu and couldn't find any supported dependency files. If we were to guess, we would say that this is not actually a project Depfu supports and has probably been activated by error.

Monorepos

Please note that Depfu currently only searches for your dependency files in the root folder. We do support monorepos and non-root files, but don't auto-detect them. If that's the case with this repo, please send us a quick email with the folder you want Depfu to work on and we'll set it up right away!

How to deactivate the project

  • Go to the Settings page of either your own account or the organization you've used
  • Go to "Installed Integrations"
  • Click the "Configure" button on the Depfu integration
  • Remove this repo (appsignal/appsignal-nodejs) from the list of accessible repos.

Please note that using the "All Repositories" setting doesn't make a lot of sense with Depfu.

If you think that this is a mistake

Please let us know by sending an email to [email protected].


This is an automated issue by Depfu. You're getting it because someone configured Depfu to automatically update dependencies on this project.

Random checksum validation fails in test suite

Sometimes a test suite run will fail with the following error:

Error: Checksum verification failed
    at Hash.<anonymous> (/home/travis/build/appsignal/appsignal-nodejs/packages/nodejs/scripts/extension.js:56:25)

Restarting the job seems to always fix the problem.

npx Install Script

Users currently install the core library and integrations separately:

yarn add @appsignal/nodejs @appsignal/express

This allows the library to be modular, reducing size and complexity of the core library as well as enabling us to prefer framework-specific integrations where possible (like the express integration) rather introducing complex monkey-patching solutions that could conflict with other modules:

express().use(expressMiddleware(appsignal))

Such an integration is not possible to do automatically, as it requires the user to instantiate an object that is in a lexical scope we can't access.

However, this means that users have to remember to install any integrations, and in some projects with a large amount of dependencies, this could amount to quite a number of additional packages to remember to install.

This proposal is to add an npx command to install, rather than use npm install/yarn add directly (the user could still do this if they know what the're doing).

npx appsignal

The script would do the following:

  • Add the latest @appsignal/nodejs to package.json
  • Read package.json and add integrations for known packages to package.json
  • Run yarn install

This script could be run again at any time to install packages for any new modules the user might have installed.

With this change, we'd like to achieve the following:

  • Improve user convenience

Next Steps

  • Gather requirements
  • Discuss potential technical solutions
  • Schedule for implementation

Missing type import

Get this message when trying to build my project which includes Appsignal.

node_modules/@appsignal/nodejs/dist/instrument.d.ts:1:18 - error TS7016: Could not find a declaration file for module 'require-in-the-middle'. './node_modules/require-in-the-middle/index.js' implicitly has an 'any' type.
  Try `npm install @types/require-in-the-middle` if it exists or add a new declaration (.d.ts) file containing `declare module 'require-in-the-middle';`

1 import Hook from "require-in-the-middle";
                   ~~~~~~~~~~~~~~~~~~~~~~~

General GC metrics from Node/V8

appsignal_start_transaction requires long parameter gc_duration_ms, which is documented as "the current garbage collection duration in milliseconds".

Node.js does not expose this number in its public API, which means we may have to write further code in C/C++ to get those values from V8, and in fact this seems like what others have done.

We can import v8.h from the same place as we import node.h, however, per the docs, we will likely lose ABI stability. This may or may not matter to us.

V8 also has separate types of GC. There are 3 types of GC events in V8:

  • kGCTypeMarkSweepCompact
  • kGCTypeScavenge
  • kGCTypeAll

We will need to decide which of these events are relevant to our use case.

ECMAScript module support

Yesterday, support for ECMAScript modules was merged into Node.js. This represents a fundamental change in the way that modules work in Node.js, and subsequently, a change that will require us to add support for it in this library in order to support future modules.

Currently, when importing a CommonJS module with require(), we need to be able to monkeypatch Node modules at require time in order to instrument them, and traditionally this has been done by monkeypatching the Module internals themselves in order to catch and modify modules that we need to integrate into.

ECMAScript modules has a different method for handling this that we will also need to take into account. This YouTube talk outlines the steps necessary.

Next.js integration

I've been doing some work on getting this to integrate with Next.js.

We were using a custom server with Node's default HTTP server implementation http as described in https://nextjs.org/docs/advanced-features/custom-server . However, this wasn't correctly capturing the route paths, naming all spans as GET [unknown route]. Moved to using a custom express server instead.

Had to change the default express instrumentation a bit, so made our own middleware, like so:

const { parse } = require('url');

function expressMiddleware(appsignal) {
  return function (req, res, next) {
    const tracer = appsignal.tracer();
    const rootSpan = tracer.currentSpan();

    if (!rootSpan) {
      return next();
    }

    if (req.params.password) {
      rootSpan.setSampleData('params', {
        ...req.params,
        password: '[FILTERED]',
      });
    } else {
      rootSpan.setSampleData('params', req.params);
    }

    return tracer.withSpan(rootSpan, (span) => {
      const originalEnd = res.end;

      tracer.wrapEmitter(req);
      tracer.wrapEmitter(res);

      res.end = function (...args) {
        res.end = originalEnd;

        const { method = 'GET' } = req;

        // if there is no error passed to `next()`, the span name will
        // be updated to match the current path
        span.setName(`${method} ${parse(req.originalUrl).pathname}`);

        span.set('method', method).set('status_code', res.statusCode);
        span.set('qs', req.query);

        return res.end.apply(this, args);
      };

      return next();
    });
  };
}

function expressErrorHandler(appsignal) {
  return function (err, req, res, next) {
    const span = appsignal.tracer().currentSpan();

    if (!span) {
      return next();
    }

    // if there's no `status` property, forward the error
    // we also ignore client errors here
    if (err && (!err.status || (err.status && err.status >= 500))) {
      span.addError(err);
    }

    return next(err);
  };
}

module.exports = {
  expressMiddleware,
  expressErrorHandler,
};

Relevant changes are the insertion of the querystring arguments as part of the span and usage of parse(req.originalUrl).pathname instead of req.route.path. req.route.path is actually the path of the route that matches, not the path portion of the original URL. Because Next.js implements its own handler function, we must match on all * routes and pass that on to the default handler function. See https://github.com/zeit/next.js/blob/canary/examples/custom-server-express/server.js for an example.

Right now, we have spans in AppSignal with request duration, however can't find the span metadata anywhere. Also, the span itself has no drilldown available, listing a single unknown event.

Ignoring a core Node instrumentation

The client should be able to turn instrumentation off for internal Node.js modules if the user doesn't require it. This could be handled via a config option.

const { Appsignal } = require("@appsignal/nodejs")

const appsignal = new Appsignal({
  active: true,
  name: "<YOUR APPLICATION NAME>"
  apiKey: "<YOUR API KEY>",
  ignoreInstrumentation: ["http"]
})

Support custom Webpack SSR solutions

Hello,

I'm trying to integrate this lib into node app which uses webpack.

However it all ends up with an error:

ERROR in ./node_modules/@appsignal/nodejs-ext/build/Release/extension.node 1:0
Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
 @ ./node_modules/@appsignal/nodejs-ext/dist/index.js 2:17-59
 @ ./node_modules/@appsignal/nodejs/dist/extension.js
 @ ./node_modules/@appsignal/nodejs/dist/agent.js
 @ ./node_modules/@appsignal/nodejs/dist/client.js
 @ ./node_modules/@appsignal/nodejs/dist/index.js
 @ ./src/server/app.tsx
 @ ./src/server/index.ts

Help would be much appreciated :)

Appsignal requires options parameter

In the documentation (and reading through the code) it seems like the intent is that all parameters to the main Appsignal entrypoint are optional -- they can be supplied with environment variables. However, the Typescript definition doesn't let you leave out the argument entirely, and if you do supply it, you are required to give app name and API key -- these values will override the environment variables.

I'd like to use this with app name fixed in the code, but the API key and environment name supplied in environment variables. I could do this by hand (Process.env) but it seems like this is an oversight?

Depfu Error: No dependency files found

Hello,

We've tried to activate or update your repository on Depfu and couldn't find any supported dependency files. If we were to guess, we would say that this is not actually a project Depfu supports and has probably been activated by error.

Monorepos

Please note that Depfu currently only searches for your dependency files in the root folder. We do support monorepos and non-root files, but don't auto-detect them. If that's the case with this repo, please send us a quick email with the folder you want Depfu to work on and we'll set it up right away!

How to deactivate the project

  • Go to the Settings page of either your own account or the organization you've used
  • Go to "Installed Integrations"
  • Click the "Configure" button on the Depfu integration
  • Remove this repo (appsignal/appsignal-nodejs) from the list of accessible repos.

Please note that using the "All Repositories" setting doesn't make a lot of sense with Depfu.

If you think that this is a mistake

Please let us know by sending an email to [email protected].


This is an automated issue by Depfu. You're getting it because someone configured Depfu to automatically update dependencies on this project.

Ignores APPSIGNAL_APP_ENV environment variable

It seems that the APPSIGNAL_APP_ENV environment variable doesn't have the effect it's supposed to (as per the other integrations). Our staging environment runs with NODE_ENV set to production, which is fairly common. On our Ruby services we use APPSIGNAL_APP_ENV to set it to the right thing. This doesn't work in the Node integration.

Looking through the code, it seems that the APPSIGNAL_APP_ENV environment variable is mapped through to env on the options, but this isn't actually ever used -- elsewhere, NODE_ENV is used, defaulting to development.

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.