-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Observability] Create context container to enable Observability plugin registry function #68642
[Observability] Create context container to enable Observability plugin registry function #68642
Conversation
Pinging @elastic/apm-ui (Team:apm) |
retest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't comment on the APM side of things, but this looks like a good start. For the data fetching to work, though, the service also needs to expose a way for the solutions to register custom context providers, which make data access available within their respective data fetcher functions.
retest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're getting close 📈 I really like the symmetric substructure of the obs data service 👍 I just left a few suggestions about making its API more consistent below.
x-pack/plugins/observability/public/typings/data_access_service.d.ts
Outdated
Show resolved
Hide resolved
Can we bump this type up and export/share it in all the places we need to use these names for shared interfaces between the apps? https://github.com/elastic/kibana/blob/master/x-pack/plugins/observability/public/hooks/use_track_metric.tsx#L20 |
I thought "context" was provided by Kibana core, with pre-scoped clients etc similar to how HTTP routing handlers work. If we are providing the values for context, do we know exactly what values we are going to provide so that all apps have what they need to make their calls? This part is still really fuzzy to me. |
Maybe I misunderstand your question, but each plugin should define its own context. The Observability itself won't add any information. // plugin.ts
public setup(core: CoreSetup, plugins: ApmPluginSetupDeps) {
plugins.observability.dataAccess.registerContext(
this.initializerContext.opaqueId,
'createCallApmApi',
() => createCallApmApi
);
plugins.observability.dataAccess.registerProvider(
this.initializerContext.opaqueId,
'apm',
getObservabilityChartData
);
} |
Got it, so I'm trying to wrap my head around these layers of abstraction. How are these two things different: 1: import { callApi } from '../callApi';
const getChartData = (context, { start, end }) => {
context.callApi({ start, end, otherArgs });
}
plugins.observability.dataAccess.registerContext(
this.initializerContext.opaqueId,
'callApi',
() => callApi
);
plugins.observability.dataAccess.registerProvider(
this.initializerContext.opaqueId,
'apm',
getChartData
); vs 2: import { callApi } from '../callApi';
const getChartData = (context, { start, end }) => {
callApi({ start, end, otherArgs });
}
plugins.observability.dataAccess.registerProvider(
this.initializerContext.opaqueId,
'apm',
getChartData
); |
Conceptually, none. In both cases, you'll have But what if your public setup(core: CoreSetup, plugins: ApmPluginSetupDeps) {
plugins.observability.dataAccess.registerProvider(
this.initializerContext.opaqueId,
'apm',
() => {
// do anything cool
const isSecurityEnabled = plugins.security?.license.isEnabled();
}
);
} And if you want to isolate your function in another file, you wouldn't have the security plugin in scope, so you'd do: //plugin.ts
public setup(core: CoreSetup, plugins: ApmPluginSetupDeps) {
plugins.observability.dataAccess.requiresAppContext(
this.initializerContext.opaqueId,
() => ({
security: plugins.security,
})
);
plugins.observability.dataAccess.registerProvider(
this.initializerContext.opaqueId,
'apm',
getChartData
);
}
//get_chart_data.ts
const getChartData = (context, { start, end }) => {
const isSecurityEnabled = context.security?.license.isEnabled();
// do anything cool
} |
@elasticmachine merge upstream |
Right, ok. And if this function was being used in your own plugin, you could pass it the things it needs directly or using some React context/hook combination. The alternative would be to have the observability plugin call each registered function with a set of commonly needed interfaces, e.g. licensing, security, es client, etc and then the registered methods would use them as passed in. I can see the advantage of defining your own context giving you the ultimate flexibility in what your registered function can do, but it seems to come at the expense of making everything much harder to follow. I'm curious if anyone else has thoughts on this pattern? |
Another thought: at the very least if each calling plugin need to pre-register its own function's context value, could it at least happen inside of plugins.observability.dataAccess.registerProvider({
opaqueId: this.initializerContext.opaqueId,
name: 'apm',
handler: getChartData,
providedContext: { // or just context, whatever
getData: () => {}, // all provided values here
}
}); I'm not sure how much control over this API we have vs what comes from the registry context tooling we are using from core, but I think that at least might make it a little clearer how these things are related... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good for a first pass. I share some of @jasonrhodes concerns about the indirection and complexity, but don't have any constructive feedback for how we would do it differently. This is a great place to start and evolve from as needs change and we have experience using this in our plugins.
We can do it. I can pre-register some plugins in advance.
I will create an example as you propose. |
@jasonrhodes I made the changes as you suggested, it looks simpler in my opinion. Take a look here 0fcbcd2 plugins.observability.dataAccess.registerProvider({
pluginOpaqueId: this.initializerContext.opaqueId,
dataType: 'apm',
handler: getObservabilityChartData,
providedContext: {
licensing: plugins.licensing,
home: plugins.home,
},
}); Then to access it in the handler function you'd do WDYT? |
Cool so if I understand correctly, in this case we'd need to explicitly type the contract that the obs plugin provides when it calls these dataFetcher callbacks, right? Do we know what that contract would need to look like? |
A quick grep shows it's used outside of Inside
I'm surprised the number is so low. I would have expected things like the task manager (and thereby alerting), visualizations, expression functions and so on to use it to for their registries, but they implement custom mechanisms. Maybe because they predate the context service? I think our use case is a perfect match, but if it turns out that not using it is simpler and easier I can follow that argument. |
What's the argument against coupling this to the obs plugin life-cycle? An implicit singleton seem unnecessarily hacky. I hope we're not conflating this with the context container topic. Those are different aspects. |
@jasonrhodes I believe this is what you want:
|
@cauemarcondes ok so if a dataFetcher needs access to e.g. the security plugin, etc. it will need to manage that itself via a closure when it registers the fetcher? I thought we were going to explore providing a contract of core APIs at call time, but that's less flexible than letting the apps manage that for themselves, so I'm okay with either. |
Correct. |
The context container approach is overly complex for what we need imo. If we need the additional complexity down the road we can always add it. But let's start simple if possible. |
x-pack/plugins/observability/public/typings/data_fetcher/index.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM as a great starting point, thanks @cauemarcondes! I think we will probably realize we are all sharing enough of the same deps that we may eventually provide them via the FetchDataParams
as a common contract/interface, but we can definitely add that later once we see how each solution is building its fetch data function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@elasticmachine merge upstream |
💚 Build SucceededBuild metrics@kbn/optimizer bundle module count
page load asset sizebeta
History
To update your PR or re-run it, just comment with: |
…in registry function (elastic#68642) * creating observability context registry * adding registryContext * addressing PR comments * addressing PR comments * adding context to registry provider * adding obs own registry * refactoring * refactoring * fixing types * removing apm code Co-authored-by: Elastic Machine <[email protected]>
* master: (91 commits) [Search][BUG] Call wrong search strategy recursively in async search (elastic#69116) [Observability] Create context container to enable Observability plugin registry function (elastic#68642) Rename space id for disabled index pattern test (elastic#68990) skip flaky suite (elastic#63339) Resolver Light Theme And Kibana Integration (elastic#67859) [kbn/dev-utils] expose public tooling_log module (elastic#68868) index pattern(s) take dependencies as object (elastic#69055) include ci-stats metrics in pr comment (elastic#68563) Bump webpack packages (elastic#68716) [Uptime] Fixed metric query broken because of missing mapping (elastic#68999) Added cloud as an optional dependency (elastic#69050) Fixed all external links (elastic#68614) [DOCS] Reorganizes doc nav to match new Kibana nav (elastic#69069) [Endpoint] Using the stats provided by the backend for resolver UI (elastic#68577) [DOCS] Removees 8.0 from Upgrade Assistant docs (elastic#69067) [ML] Fix cloud deployment ID check (elastic#68695) [DOCS] Move metrics app content to metrics monitoring guide (elastic#69033) Add ingest manager topic to docs (elastic#68980) [SECURITY SOLUTION] EMT-401: add policy data to metadata and fix tests (elastic#68582) [DOCS] Fixes POST request for saved objects (elastic#69036) ...
…in registry function (#68642) (#69125) * creating observability context registry * adding registryContext * addressing PR comments * addressing PR comments * adding context to registry provider * adding obs own registry * refactoring * refactoring * fixing types * removing apm code Co-authored-by: Elastic Machine <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
* master: (60 commits) Re-enable mistakenly skipped tests. (elastic#69123) [Search][BUG] Call wrong search strategy recursively in async search (elastic#69116) [Observability] Create context container to enable Observability plugin registry function (elastic#68642) Rename space id for disabled index pattern test (elastic#68990) skip flaky suite (elastic#63339) Resolver Light Theme And Kibana Integration (elastic#67859) [kbn/dev-utils] expose public tooling_log module (elastic#68868) index pattern(s) take dependencies as object (elastic#69055) include ci-stats metrics in pr comment (elastic#68563) Bump webpack packages (elastic#68716) [Uptime] Fixed metric query broken because of missing mapping (elastic#68999) Added cloud as an optional dependency (elastic#69050) Fixed all external links (elastic#68614) [DOCS] Reorganizes doc nav to match new Kibana nav (elastic#69069) [Endpoint] Using the stats provided by the backend for resolver UI (elastic#68577) [DOCS] Removees 8.0 from Upgrade Assistant docs (elastic#69067) [ML] Fix cloud deployment ID check (elastic#68695) [DOCS] Move metrics app content to metrics monitoring guide (elastic#69033) Add ingest manager topic to docs (elastic#68980) [SECURITY SOLUTION] EMT-401: add policy data to metadata and fix tests (elastic#68582) ...
closes #68534
Creates a context registry on the Observability plugin. The idea is that any plugin can registry its own way to fetch data.
Registring:
terminateAfter: 1
can be used in the ES request since no data needs to be returned.read
privilege to the indices, it should return false.