Skip to content

Commit

Permalink
Merge branch 'feature/fiberless' of https://github.com/monti-apm/mont…
Browse files Browse the repository at this point in the history
…i-apm-agent into 3.0-disable-await-detector
  • Loading branch information
alisnic committed Dec 26, 2024
2 parents e7a63a6 + 98c138e commit d268e44
Show file tree
Hide file tree
Showing 31 changed files with 1,101 additions and 77 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ overrides:
'@typescript-eslint/no-empty-function': 0
'@typescript-eslint/no-extra-semi': 0
rules:
arrow-body-style: 0
arrow-parens: 0
prefer-arrow-callback: 0
newline-before-return: 0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
uses: actions/setup-node@v4
with:
cache: 'npm'
node-version: 18
node-version: '22.x'

- name: Install Dependencies
run: |
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
.build*
node_modules/
.npm
.npm/.package-garbage-*
smart.lock
versions.json
.idea
.eslintcache
packages/
.envrc
/packages/*
/packages/*
1 change: 1 addition & 0 deletions .npm/package/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
7 changes: 7 additions & 0 deletions .npm/package/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.

You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.
139 changes: 139 additions & 0 deletions .npm/package/npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
* Tracer supports parallel events
* Improve support for proxies

* Create custom traces with `Monti.traceJob`
* Add monitoring for job queues, cron jobs, and custom functions
* Add `disableInstrumentation` option
* Use websockets to start cpu profiling
* Support for recording heap snapshots

## v2.49.4
July 11, 2024

Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ You should use the same method that you used to give the agent the app id and se
| stalledTimeout | STALLED_TIMEOUT | 1800000 (30m) | Timeout used to detect when methods and subscriptions might be stalled (have been running for a long time and might never return). The value is in milliseconds, and can be disabled by setting it to 0 |
| proxy | MONTI_OPTIONS_PROXY | none | Allows you to connect to Monti APM using a proxy |
| disableInstrumentation | DISABLE_INSTRUMENTATION | false | Disables recording most metrics and traces. Can be configured using Meteor.settings, or by env variable |
| disableAwaitDetector | DISABLE_AWAIT_DETECTOR | false | Disables recording of async events.


### Traces
Expand Down
12 changes: 9 additions & 3 deletions lib/async/als.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ export const getId = () => id++;

export const MontiAsyncStorage = new AsyncLocalStorage();

export function createStore () {
return {
id: getId(),
info: null,
activeEvent: null
};
}

export const runWithALS = (
fn,
) => function (...args) {
const store = { id: getId(), info: null, activeEvent: null };

return MontiAsyncStorage.run(store, () => fn.apply(this, args));
return MontiAsyncStorage.run(createStore(), () => fn.apply(this, args));
};

export const MontiEnvironmentVariable = new AsyncLocalStorage();
Expand Down
53 changes: 29 additions & 24 deletions lib/auto_connect.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import { Meteor } from 'meteor/meteor';

Kadira._connectWithEnv = function () {
const options = Kadira._parseEnv(process.env);
if (options.appId && options.appSecret) {
const envOptions = Kadira._parseEnv(process.env);
const montiSettings = Meteor.settings.monti || Meteor.settings.kadira;

Kadira._connectWithEnv = function (env) {
if (env.appId && env.appSecret) {
Kadira.connect(
options.appId,
options.appSecret,
options
env.appId,
env.appSecret,
env
);

Kadira.connect = function () {
throw new Error('Kadira has been already connected using credentials from Environment Variables');
throw new Error('Monti APM: already connected using credentials from Environment Variables');
};
}
};


Kadira._connectWithSettings = function () {
const montiSettings = Meteor.settings.monti || Meteor.settings.kadira;

Kadira._connectWithSettings = function (settings) {
if (
montiSettings &&
montiSettings.appId &&
montiSettings.appSecret
settings &&
settings.appId &&
settings.appSecret
) {
Kadira.connect(
montiSettings.appId,
montiSettings.appSecret,
montiSettings.options || {}
settings.appId,
settings.appSecret,
settings.options || {}
);

Kadira.connect = function () {
throw new Error('Kadira has been already connected using credentials from Meteor.settings');
throw new Error('Monti APM: already connected using credentials from Meteor.settings');
};
}
};
Expand All @@ -40,11 +40,16 @@ Kadira._connectWithSettings = function () {
* We need to instrument this right away, and it's okay
* One reason for this is to call `setLabels()` function
* Otherwise, CPU profile can't see all our custom labeling
*
* Previously there was two log messages (one for instrumentation,
* and another for connection), this way we merged both of them.
*/
Kadira._startInstrumenting(function () {
Kadira._connectWithEnv();
Kadira._connectWithSettings();
});
let settingsOptions = montiSettings && montiSettings.options || {};
if (
envOptions.disableInstrumentation || settingsOptions.disableInstrumentation
) {
// eslint-disable-next-line no-console
console.log('Monti APM: Instrumentation is disabled. Metrics and traces will not be recorded.');
} else {
Kadira._startInstrumenting();
}

Kadira._connectWithEnv(envOptions);
Kadira._connectWithSettings(montiSettings);
6 changes: 6 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ export const EventType = {
Wait: 'wait',
Email: 'email',
};

export const JobType = {
CPU_PROFILE: 'cpuProfile',
HEAP_SNAPSHOT: 'heapSnapshot',
ALLOCATION_PROFILE: 'allocationProfile'
};
4 changes: 4 additions & 0 deletions lib/environment_variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ Kadira._parseEnv._options = {
name: 'disableNtp',
parser: Kadira._parseEnv.parseBool,
},
MONTI_DISABLE_INSTRUMENTATION: {
name: 'disableInstrumentation',
parser: Kadira._parseEnv.parseBool
},
MONTI_OPTIONS_DISABLE_AWAIT_DETECTOR: {
name: 'disableAwaitDetector',
parser: Kadira._parseEnv.parseBool,
Expand Down
53 changes: 53 additions & 0 deletions lib/hijack/agenda.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { checkModuleUsed } from './commonjs-utils';

export function wrapAgenda () {
Meteor.startup(() => {
if (checkModuleUsed('@hokify/agenda')) {
instrumentAgendaTs();
}
if (checkModuleUsed('agenda')) {
instrumentAgenda();
}
});
}

function instrumentAgendaTs () {
// eslint-disable-next-line global-require
let agenda = require('@hokify/agenda');
let Job = agenda.Job;

instrumentJob(Job.prototype);
}

function instrumentAgenda () {
// eslint-disable-next-line global-require
let Job = require('agenda/dist/job').Job;
instrumentJob(Job.prototype);
}

function instrumentJob (JobMethods) {
let oldSaveJob = JobMethods.save;
JobMethods.save = function () {
let id = this.attrs._id;

if (!id) {
let name = this.attrs.name;
Kadira.models.jobs.trackNewJob(name);
}

return oldSaveJob.apply(this, arguments);
};

let oldRun = JobMethods.run;
JobMethods.run = function (...args) {
let name = this.attrs.name;
let waitTime = Date.now() - this.attrs.nextRunAt;
let details = {
name,
waitTime,
data: this.attrs.data
};

return Kadira.traceJob(details, () => oldRun.apply(this, args));
};
}
Loading

0 comments on commit d268e44

Please sign in to comment.