mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Feature Flags] Add APM transaction + better example code (#199671)
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
803738fa0c
commit
93d7044919
5 changed files with 122 additions and 42 deletions
|
@ -8,24 +8,15 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiHorizontalRule,
|
||||
EuiPageTemplate,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiLink,
|
||||
EuiListGroup,
|
||||
EuiListGroupItem,
|
||||
} from '@elastic/eui';
|
||||
import { EuiHorizontalRule, EuiPageTemplate, EuiTitle, EuiText, EuiLink } from '@elastic/eui';
|
||||
import type { CoreStart, FeatureFlagsStart } from '@kbn/core/public';
|
||||
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import {
|
||||
FeatureFlagExampleBoolean,
|
||||
FeatureFlagExampleNumber,
|
||||
FeatureFlagExampleString,
|
||||
} from '../../common/feature_flags';
|
||||
import { PLUGIN_NAME } from '../../common';
|
||||
import {
|
||||
FeatureFlagsFullList,
|
||||
FeatureFlagsReactiveList,
|
||||
FeatureFlagsStaticList,
|
||||
} from './feature_flags_list';
|
||||
|
||||
interface FeatureFlagsExampleAppDeps {
|
||||
featureFlags: FeatureFlagsStart;
|
||||
|
@ -34,16 +25,6 @@ interface FeatureFlagsExampleAppDeps {
|
|||
}
|
||||
|
||||
export const FeatureFlagsExampleApp = ({ featureFlags }: FeatureFlagsExampleAppDeps) => {
|
||||
// Fetching the feature flags synchronously
|
||||
const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false);
|
||||
const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red');
|
||||
const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1);
|
||||
|
||||
// Use React Hooks to observe feature flags changes
|
||||
const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false));
|
||||
const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red'));
|
||||
const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1));
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPageTemplate>
|
||||
|
@ -67,22 +48,21 @@ export const FeatureFlagsExampleApp = ({ featureFlags }: FeatureFlagsExampleAppD
|
|||
.
|
||||
</p>
|
||||
<EuiHorizontalRule />
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The <strong>observed</strong> feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num$}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
<h3>Rendered separately</h3>
|
||||
<p>
|
||||
Each list are 2 different components, so only the reactive one is re-rendered when the
|
||||
feature flag is updated and the static one keeps the value until the next refresh.
|
||||
</p>
|
||||
<FeatureFlagsStaticList featureFlags={featureFlags} />
|
||||
<FeatureFlagsReactiveList featureFlags={featureFlags} />
|
||||
<EuiHorizontalRule />
|
||||
<h3>Rendered together</h3>
|
||||
<p>
|
||||
`useObservable` causes a full re-render of the component, updating the{' '}
|
||||
<i>statically</i>
|
||||
evaluated flags as well.
|
||||
</p>
|
||||
<FeatureFlagsFullList featureFlags={featureFlags} />
|
||||
</EuiText>
|
||||
</EuiPageTemplate.Section>
|
||||
</EuiPageTemplate>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { EuiListGroup, EuiListGroupItem } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import type { FeatureFlagsStart } from '@kbn/core-feature-flags-browser';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import {
|
||||
FeatureFlagExampleBoolean,
|
||||
FeatureFlagExampleNumber,
|
||||
FeatureFlagExampleString,
|
||||
} from '../../common/feature_flags';
|
||||
|
||||
export interface FeatureFlagsListProps {
|
||||
featureFlags: FeatureFlagsStart;
|
||||
}
|
||||
|
||||
export const FeatureFlagsStaticList = ({ featureFlags }: FeatureFlagsListProps) => {
|
||||
// Fetching the feature flags synchronously
|
||||
const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false);
|
||||
const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red');
|
||||
const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1);
|
||||
|
||||
return (
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export const FeatureFlagsReactiveList = ({ featureFlags }: FeatureFlagsListProps) => {
|
||||
// Use React Hooks to observe feature flags changes
|
||||
const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false));
|
||||
const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red'));
|
||||
const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1));
|
||||
|
||||
return (
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The <strong>observed</strong> feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num$}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export const FeatureFlagsFullList = ({ featureFlags }: FeatureFlagsListProps) => {
|
||||
// Fetching the feature flags synchronously
|
||||
const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false);
|
||||
const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red');
|
||||
const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1);
|
||||
|
||||
// Use React Hooks to observe feature flags changes
|
||||
const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false));
|
||||
const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red'));
|
||||
const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1));
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
<EuiListGroup>
|
||||
<p>
|
||||
The <strong>observed</strong> feature flags are:
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleBoolean}: ${bool$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleString}: ${str$}`} />
|
||||
<EuiListGroupItem label={`${FeatureFlagExampleNumber}: ${num$}`} />
|
||||
</p>
|
||||
</EuiListGroup>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -20,5 +20,6 @@
|
|||
"@kbn/core-plugins-server",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/developer-examples-plugin",
|
||||
"@kbn/core-feature-flags-browser",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ The service is always enabled, however, it will return the fallback value if a f
|
|||
Kibana only registers a provider when running on Elastic Cloud Hosted/Serverless. And even in those scenarios, we expect that some customers might
|
||||
have network restrictions that might not allow the flags to evaluate. The fallback value must provide a non-broken experience to users.
|
||||
|
||||
:warning: Feature Flags are considered dynamic configuration and cannot be used for settings that require restarting Kibana.
|
||||
⚠️Feature Flags are considered dynamic configuration and cannot be used for settings that require restarting Kibana.
|
||||
One example of invalid use cases are settings used during the `setup` lifecycle of the plugin, such as settings that define
|
||||
if an HTTP route is registered or not. Instead, you should always register the route, and return `404 - Not found` in the route
|
||||
handler if the feature flag returns a _disabled_ state.
|
||||
|
|
|
@ -68,7 +68,15 @@ export class FeatureFlagsService {
|
|||
if (this.isProviderReadyPromise) {
|
||||
throw new Error('A provider has already been set. This API cannot be called twice.');
|
||||
}
|
||||
const transaction = apm.startTransaction('set-provider', 'feature-flags');
|
||||
this.isProviderReadyPromise = OpenFeature.setProviderAndWait(provider);
|
||||
this.isProviderReadyPromise
|
||||
.then(() => transaction?.end())
|
||||
.catch((err) => {
|
||||
this.logger.error(err);
|
||||
apm.captureError(err);
|
||||
transaction?.end();
|
||||
});
|
||||
},
|
||||
appendContext: (contextToAppend) => this.appendContext(contextToAppend),
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue