newrelic / node-newrelic

New Relic Node.js agent code base. Developers are welcome to create pull requests here, please see our contributing guidelines. For New Relic technical support, please go to http://support.newrelic.com.
Apache License 2.0
966 stars 394 forks source link

Neo4J instrumentation #647

Open artur-ma opened 3 years ago

artur-ma commented 3 years ago

Is your feature request related to a problem? Please describe.

We are using neo4j DB in production but we can not see any data/timings on neo4j transactions

Feature Description

Neo4J instrumentation to be added for official Node client

Describe Alternatives

The only thing we can do is to wrap the call to Neo4j with a separate segment

Priority

Really Want

carlo-808 commented 3 years ago

@artur-ma Thank you for the feature request! We'll get this prioritized with the other requests.

artur-ma commented 3 years ago

Maybe this code can help

const instrumentNeoQueryRunner = (shim, cls) => {
  const proto = cls.default.prototype;

  if (!proto) {
    return false
  }

  shim.setDatastore("Neo")

  shim.wrap(proto, 'run', function (shim, fn) {
    return function wrappedRun() {
      const args = shim.toArray(arguments)

      const response = fn.apply(this, args)
      const originalSubscribe = response.subscribe;

      response.subscribe = function (observer) {
        if (shim.isFunction(observer.onCompleted) && !shim.isWrapped(observer.onCompleted)) {
          Object.assign(Object.assign({}, observer), { 
            onCompleted: shim.bindSegment(observer.onCompleted)
          });
        }

        if (shim.isFunction(observer.onError) && !shim.isWrapped(observer.onError)) {
          Object.assign(Object.assign({}, observer), { 
            onError: shim.bindSegment(observer.onError)
          });
        }

        return originalSubscribe.call(this, observer);
      }

      return response;
    }
  });

  shim.recordOperation(proto, 'run', function (shim, original, name, args) {
    return {
      name: this?._connectionHolder?._mode || 'QUERY',
    }
  })
}

module.exports = (shim) => {    
  const Transaction = require('neo4j-driver/lib/transaction');
  const Session = require('neo4j-driver/lib/session');

  instrumentNeoQueryRunner(shim, Transaction);
  instrumentNeoQueryRunner(shim, Session);
};

The idea was taken from here:

https://github.com/aspecto-io/opentelemetry-ext-js/tree/master/packages/instrumentation-neo4j

carlo-808 commented 3 years ago

Thank you @artur-ma ! This will definitely save us some time once we get to this work.

bizob2828 commented 1 month ago

still valid

workato-integration[bot] commented 1 month ago

https://new-relic.atlassian.net/browse/NR-292112