Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extension function calls safety #556

Open
1 of 3 tasks
tombruijn opened this issue Jan 19, 2022 · 4 comments
Open
1 of 3 tasks

Extension function calls safety #556

tombruijn opened this issue Jan 19, 2022 · 4 comments
Labels

Comments

@tombruijn
Copy link
Member

tombruijn commented Jan 19, 2022

When the extension fails to install, or has been installed for a not matching architecture, function calls to the extension may fail.

For example, when running the macOS build on a Linux docker image, calling the diagnose function results in the following:

$ npx @appsignal/cli diagnose
🔭 Checking your package.json for @appsignal/nodejs...
✅ Found it! Running the diagnose tool...
AppSignal extension not loaded. This could mean that your current environment isn't supported, or that another error has occurred. // This is no longer present after PR #554 
/integration/packages/nodejs/dist/extension.js:68
        return extension_wrapper_1.extension.runningInContainer();
                                             ^

TypeError: extension_wrapper_1.extension.runningInContainer is not a function
    at Extension.runningInContainer (/integration/packages/nodejs/dist/extension.js:68:46)
    at DiagnoseTool.getHostData (/integration/packages/nodejs/dist/diagnose.js:64:84)
    at DiagnoseTool.generate (/integration/packages/nodejs/dist/diagnose.js:35:24)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at async Diagnose.run (/integration/packages/nodejs/dist/cli/diagnose.js:18:22)

(Example run on the main branch before PR #554 is merged. 58f1ae0)

This shouldn't happen. It shouldn't cause an error.

When the extension module is not present it should not call functions that may fail.

To do

  • Fix call to runningInContainer as in the example. PR Fix extension function fallbacks #557
  • Double check any other extension function calls for safety when the extension is not loaded.
    • Create a noop function instead? This is partially done by the extension wrapper, but makes available way too few functions to catch all undefined behavior.
  • Update ExtensionWrapper to return "noop" functions for all extension functions if it fails to load.
@tombruijn tombruijn added the bug label Jan 19, 2022
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
tombruijn added a commit that referenced this issue Jan 19, 2022
As reported in #556, when the extension is not installed or fails to
load, calls to certain extension functions will fail. The issue mentions
the `runningInContainer` broken being broken on the main branch.

PR #554 also removes some safety checks that cause the same issue for
the `diagnoseRaw` function. Those safety checks were removed because
they did not what expected, tracking if the extension was running or
not.

For both functions I've implemented a no-operations function. This will
fix any errors on calls to these functions. Other functions that call
these functions need to handle receiving no return value.

Part of #556, but doesn't fix it entirely. We should call more function
calls. These ones were the most obvious ones.

Based on PR #554.
@tombruijn
Copy link
Member Author

The Node.js integration doesn't impelement "noop" functions for all extension functions like the other integrations do. That may be a safer way to solve this issue, and doesn't require checks wherever we call the extension functions.

Creating a NoopExtension class that gets initialized from the extension wrapper when the extension fails to load may be a good solution here.

@tombruijn
Copy link
Member Author

tombruijn commented Jan 27, 2022

I need to check all the places these attributes on the ExtensionWrapper can get called. The extension wrapper seems to be the most direct way to interact with the extension.

extension: any
span: any
datamap: any
dataarray: any
metrics: any

It looks like the Span extension interaction is all hidden away through noop objects if it's not available. It's different than what I'm used to from the Elixir and Ruby integrations, where we stub out the extension functions and leave all the other functionality intact. It now is is a little difficult to follow sometimes what the data flow is, when the extension isn't loaded.

We can choose to remove all the noop objects in favor of only stubbing out the extension functions if that's easier.


My journey notes so far:

The BaseSpan object is the only thing that interacts with the "span" extension class. Which we then have to rely on, that nothing calls that BaseSpan ever, if the extension is not loaded.

import { span } from "./extension_wrapper"

If the extension isn't loaded, it will return NoopSpans, because it will return the NoopTracer.

It can return "NoopSpan"s here if no (root) span is currently active.

return this.#scopeManager.active() || new NoopSpan()

This check reads a little weird. It uses the noopspan as a nil check if no extension is present, while it's also used when the extension isn't loaded. We should rather ask "is there a root span? If no, create a new one". Move that behavior to the tracer or communicate it with another function call than like this.

if (tracer.currentSpan() instanceof NoopSpan) {

@tombruijn
Copy link
Member Author

I wanted to test a small refactor, taking out all the Noop* classes and letting the extension calls just do nothing. Like it's implemented in the Ruby and Elixir integrations. But I'm running into so many issues and having to write so many tests for things that should be, but currently are not, tested. I'm giving up on the project for now.

@tombruijn
Copy link
Member Author

tombruijn commented Feb 8, 2022

Created a separate issue to first improve test coverage before I can reliably try this refactor. #605

@tombruijn tombruijn removed their assignment Oct 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant