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

[ML] Adding configurable file size to file data visualizer #62752

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/common/constants/file_datavisualizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*/

export const MAX_BYTES = 104857600;
export const ABSOLUTE_MAX_BYTES = MAX_BYTES * 5;
export const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b';

// Value to use in the Elasticsearch index mapping meta data to identify the
// index as having been created by the ML File Data Visualizer.
Expand Down
16 changes: 16 additions & 0 deletions x-pack/plugins/ml/common/types/ml_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { schema, TypeOf } from '@kbn/config-schema';
import { MAX_BYTES } from '../constants/file_datavisualizer';

export const configSchema = schema.object({
file_data_visualizer: schema.object({
max_file_size_bytes: schema.number({ defaultValue: MAX_BYTES }),
}),
});

export type MlConfigType = TypeOf<typeof configSchema>;
7 changes: 6 additions & 1 deletion x-pack/plugins/ml/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/p
import { setDependencyCache, clearCache } from './util/dependency_cache';
import { setLicenseCache } from './license';
import { MlSetupDependencies, MlStartDependencies } from '../plugin';
import { MlConfigType } from '../../common/types/ml_config';

import { MlRouter } from './routing';

type MlDependencies = MlSetupDependencies & MlStartDependencies;
type MlDependencies = MlSetupDependencies &
MlStartDependencies & {
mlConfig: MlConfigType;
};

interface AppProps {
coreStart: CoreStart;
Expand Down Expand Up @@ -74,6 +78,7 @@ export const renderApp = (
http: coreStart.http,
security: deps.security,
urlGenerators: deps.share.urlGenerators,
mlConfig: deps.mlConfig,
});

const mlLicense = setLicenseCache(deps.licensing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { isFullLicense } from '../license';
import { useTimefilter, useMlKibana } from '../contexts/kibana';

import { NavigationMenu } from '../components/navigation_menu';
import { getMaxBytesFormatted } from './file_based/components/utils';

function startTrialDescription() {
return (
Expand Down Expand Up @@ -59,6 +60,8 @@ export const DatavisualizerSelector: FC = () => {
licenseManagement.enabled === true &&
isFullLicense() === false;

const maxFileSize = getMaxBytesFormatted();

return (
<Fragment>
<NavigationMenu tabId="datavisualizer" />
Expand Down Expand Up @@ -102,7 +105,8 @@ export const DatavisualizerSelector: FC = () => {
description={
<FormattedMessage
id="xpack.ml.datavisualizer.selector.importDataDescription"
defaultMessage="Import data from a log file. You can upload files up to 100 MB."
defaultMessage="Import data from a log file. You can upload files up to {maxFileSize}."
values={{ maxFileSize }}
/>
}
betaBadgeLabel={i18n.translate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '@elastic/eui';

import { ExperimentalBadge } from '../experimental_badge';
import { getMaxBytesFormatted } from '../utils';

export const WelcomeContent: FC = () => {
const toolTipContent = i18n.translate(
Expand All @@ -28,6 +29,8 @@ export const WelcomeContent: FC = () => {
}
);

const maxFileSize = getMaxBytesFormatted();

return (
<EuiFlexGroup gutterSize="xl" alignItems="center">
<EuiFlexItem grow={false}>
Expand Down Expand Up @@ -117,7 +120,8 @@ export const WelcomeContent: FC = () => {
<p>
<FormattedMessage
id="xpack.ml.fileDatavisualizer.welcomeContent.uploadedFilesAllowedSizeDescription"
defaultMessage="You can upload files up to 100 MB."
defaultMessage="You can upload files up to {maxFileSize}."
values={{ maxFileSize }}
/>
</p>
</EuiText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import { FileCouldNotBeRead, FileTooLarge } from './file_error_callouts';
import { EditFlyout } from '../edit_flyout';
import { ExplanationFlyout } from '../explanation_flyout';
import { ImportView } from '../import_view';
import { MAX_BYTES } from '../../../../../../common/constants/file_datavisualizer';
import {
getMaxBytes,
readFile,
createUrlOverrides,
processResults,
reduceData,
hasImportPermission,
} from '../utils';

import { MODE } from './constants';

const UPLOAD_SIZE_MB = 5;
Expand Down Expand Up @@ -57,6 +58,7 @@ export class FileDataVisualizerView extends Component {
this.overrides = {};
this.previousOverrides = {};
this.originalSettings = {};
this.maxFileUploadBytes = getMaxBytes();
}

async componentDidMount() {
Expand Down Expand Up @@ -93,7 +95,7 @@ export class FileDataVisualizerView extends Component {
};

async loadFile(file) {
if (file.size <= MAX_BYTES) {
if (file.size <= this.maxFileUploadBytes) {
try {
const fileContents = await readFile(file);
const data = fileContents.data;
Expand All @@ -105,7 +107,6 @@ export class FileDataVisualizerView extends Component {

await this.loadSettings(data);
} catch (error) {
console.error(error);
this.setState({
loaded: false,
loading: false,
Expand Down Expand Up @@ -181,8 +182,6 @@ export class FileDataVisualizerView extends Component {
fileCouldNotBeRead: isRetry,
});
} catch (error) {
console.error(error);

this.setState({
results: undefined,
explanation: undefined,
Expand Down Expand Up @@ -287,7 +286,9 @@ export class FileDataVisualizerView extends Component {

{loading && <LoadingPanel />}

{fileTooLarge && <FileTooLarge fileSize={fileSize} maxFileSize={MAX_BYTES} />}
{fileTooLarge && (
<FileTooLarge fileSize={fileSize} maxFileSize={this.maxFileUploadBytes} />
)}

{fileCouldNotBeRead && loading === false && (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui';

import numeral from '@elastic/numeral';
import { ErrorResponse } from '../../../../../../common/types/errors';

const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b';
import { FILE_SIZE_DISPLAY_FORMAT } from '../../../../../../common/constants/file_datavisualizer';

interface FileTooLargeProps {
fileSize: number;
Expand Down Expand Up @@ -81,7 +80,7 @@ interface FileCouldNotBeReadProps {
}

export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({ error, loaded }) => {
const message = error.body.message;
const message = error?.body?.message || '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make use of getErrorMessage() from plugins/ml/common/util/errors.ts here?

return (
<EuiCallOut
title={
Expand Down Expand Up @@ -110,7 +109,7 @@ export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({ error, loaded
};

export const Explanation: FC<{ error: ErrorResponse }> = ({ error }) => {
if (!error.body.attributes?.body?.error?.suppressed?.length) {
if (!error?.body?.attributes?.body?.error?.suppressed?.length) {
return null;
}
const reason: string = error.body.attributes.body.error.suppressed[0].reason;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export {
processResults,
readFile,
reduceData,
getMaxBytes,
getMaxBytesFormatted,
} from './utils';
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
*/

import { isEqual } from 'lodash';
import numeral from '@elastic/numeral';
import { ml } from '../../../../services/ml_api_service';
import { AnalysisResult, InputOverrides } from '../../../../../../common/types/file_datavisualizer';
import {
ABSOLUTE_MAX_BYTES,
FILE_SIZE_DISPLAY_FORMAT,
} from '../../../../../../common/constants/file_datavisualizer';
import { getMlConfig } from '../../../../util/dependency_cache';

const DEFAULT_LINES_TO_SAMPLE = 1000;

Expand Down Expand Up @@ -54,6 +60,15 @@ export function reduceData(data: string, mb: number) {
return data.length >= size ? data.slice(0, size) : data;
}

export function getMaxBytes() {
const maxBytes = getMlConfig().file_data_visualizer.max_file_size_bytes;
return maxBytes < ABSOLUTE_MAX_BYTES ? maxBytes : ABSOLUTE_MAX_BYTES;
}

export function getMaxBytesFormatted() {
return numeral(getMaxBytes()).format(FILE_SIZE_DISPLAY_FORMAT);
}

export function createUrlOverrides(overrides: InputOverrides, originalSettings: InputOverrides) {
const formattedOverrides: InputOverrides = {};
for (const o in overrideDefaults) {
Expand Down
11 changes: 11 additions & 0 deletions x-pack/plugins/ml/public/application/util/dependency_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from 'kibana/public';
import { SharePluginStart } from 'src/plugins/share/public';
import { SecurityPluginSetup } from '../../../../security/public';
import { MlConfigType } from '../../../common/types/ml_config';

export interface DependencyCache {
timefilter: DataPublicPluginSetup['query']['timefilter'] | null;
Expand All @@ -42,6 +43,7 @@ export interface DependencyCache {
security: SecurityPluginSetup | null;
i18n: I18nStart | null;
urlGenerators: SharePluginStart['urlGenerators'] | null;
mlConfig: MlConfigType | null;
}

const cache: DependencyCache = {
Expand All @@ -62,6 +64,7 @@ const cache: DependencyCache = {
security: null,
i18n: null,
urlGenerators: null,
mlConfig: null,
};

export function setDependencyCache(deps: Partial<DependencyCache>) {
Expand All @@ -82,6 +85,7 @@ export function setDependencyCache(deps: Partial<DependencyCache>) {
cache.security = deps.security || null;
cache.i18n = deps.i18n || null;
cache.urlGenerators = deps.urlGenerators || null;
cache.mlConfig = deps.mlConfig || null;
}

export function getTimefilter() {
Expand Down Expand Up @@ -202,6 +206,13 @@ export function getGetUrlGenerator() {
return cache.urlGenerators.getUrlGenerator;
}

export function getMlConfig() {
if (cache.mlConfig === null) {
throw new Error("mlConfig hasn't been initialized");
}
return cache.mlConfig;
}

export function clearCache() {
console.log('clearing dependency cache'); // eslint-disable-line no-console
Object.keys(cache).forEach(k => {
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/ml/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { PluginInitializer } from 'kibana/public';
import { PluginInitializer, PluginInitializerContext } from 'kibana/public';
import './index.scss';
import {
MlPlugin,
Expand All @@ -19,6 +19,6 @@ export const plugin: PluginInitializer<
MlPluginStart,
MlSetupDependencies,
MlStartDependencies
> = () => new MlPlugin();
> = (context: PluginInitializerContext) => new MlPlugin(context);

export { MlPluginSetup, MlPluginStart };
13 changes: 12 additions & 1 deletion x-pack/plugins/ml/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
*/

import { i18n } from '@kbn/i18n';
import { Plugin, CoreStart, CoreSetup, AppMountParameters } from 'kibana/public';
import {
Plugin,
CoreStart,
CoreSetup,
AppMountParameters,
PluginInitializerContext,
} from 'kibana/public';
import { ManagementSetup } from 'src/plugins/management/public';
import { SharePluginStart } from 'src/plugins/share/public';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
Expand All @@ -19,6 +25,7 @@ import { LicenseManagementUIPluginSetup } from '../../license_management/public'
import { setDependencyCache } from './application/util/dependency_cache';
import { PLUGIN_ID, PLUGIN_ICON } from '../common/constants/app';
import { registerFeature } from './register_feature';
import { MlConfigType } from '../common/types/ml_config';

export interface MlStartDependencies {
data: DataPublicPluginStart;
Expand All @@ -34,7 +41,10 @@ export interface MlSetupDependencies {
}

export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
constructor(private readonly initializerContext: PluginInitializerContext) {}

setup(core: CoreSetup<MlStartDependencies, MlPluginStart>, pluginsSetup: MlSetupDependencies) {
const mlConfig = this.initializerContext.config.get<MlConfigType>();
core.application.register({
id: PLUGIN_ID,
title: i18n.translate('xpack.ml.plugin.title', {
Expand All @@ -57,6 +67,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
usageCollection: pluginsSetup.usageCollection,
licenseManagement: pluginsSetup.licenseManagement,
home: pluginsSetup.home,
mlConfig,
},
{
element: params.element,
Expand Down
15 changes: 15 additions & 0 deletions x-pack/plugins/ml/server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { PluginConfigDescriptor } from 'kibana/server';
import { MlConfigType, configSchema } from '../common/types/ml_config';

export const config: PluginConfigDescriptor<MlConfigType> = {
exposeToBrowser: {
file_data_visualizer: true,
},
schema: configSchema,
};
2 changes: 2 additions & 0 deletions x-pack/plugins/ml/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ import { MlServerPlugin } from './plugin';
export { MlPluginSetup, MlPluginStart } from './plugin';

export const plugin = (ctx: PluginInitializerContext) => new MlServerPlugin(ctx);

export { config } from './config';
3 changes: 0 additions & 3 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -4531,7 +4531,6 @@
"xpack.apm.settings.apmIndices.spanIndicesLabel": "スパンインデックス",
"xpack.apm.settings.apmIndices.title": "インデックス",
"xpack.apm.settings.apmIndices.transactionIndicesLabel": "トランザクションインデックス",
"xpack.apm.settings.customizeUI": "UI をカスタマイズ",
"xpack.apm.settings.customizeUI.customLink": "カスタムリンク",
"xpack.apm.settings.customizeUI.customLink.create.failed": "リンクを保存できませんでした!",
"xpack.apm.settings.customizeUI.customLink.create.failed.message": "リンクを保存するときに問題が発生しました。エラー: 「{errorMessage}」",
Expand Down Expand Up @@ -9733,7 +9732,6 @@
"xpack.ml.datavisualizer.selector.dataVisualizerTitle": "データビジュアライザー",
"xpack.ml.datavisualizer.selector.experimentalBadgeLabel": "実験的",
"xpack.ml.datavisualizer.selector.experimentalBadgeTooltipLabel": "実験的機能。フィードバックをお待ちしています。",
"xpack.ml.datavisualizer.selector.importDataDescription": "ログファイルからデータをインポートします。最大 100 MB のファイルをアップロードできます。",
"xpack.ml.datavisualizer.selector.importDataTitle": "データのインポート",
"xpack.ml.datavisualizer.selector.selectIndexButtonLabel": "インデックスを選択",
"xpack.ml.datavisualizer.selector.selectIndexPatternDescription": "既存の Elasticsearch インデックスのデータを可視化します。",
Expand Down Expand Up @@ -9984,7 +9982,6 @@
"xpack.ml.fileDatavisualizer.welcomeContent.logFilesWithCommonFormatDescription": "タイムスタンプの一般的フォーマットのログファイル",
"xpack.ml.fileDatavisualizer.welcomeContent.newlineDelimitedJsonDescription": "改行区切りの JSON",
"xpack.ml.fileDatavisualizer.welcomeContent.supportedFileFormatDescription": "ファイルデータビジュアライザーはこれらのファイル形式をサポートしています:",
"xpack.ml.fileDatavisualizer.welcomeContent.uploadedFilesAllowedSizeDescription": "最大 100 MB のファイルをアップロードできます。",
"xpack.ml.fileDatavisualizer.welcomeContent.visualizeDataFromLogFileDescription": "ファイルデータビジュアライザーは、ログファイルのフィールドとメトリックの理解に役立ちます。ファイルをアップロードして、データを分析し、 Elasticsearch インデックスにインポートするか選択できます。",
"xpack.ml.fileDatavisualizer.welcomeContent.visualizeDataFromLogFileTitle": "ログファイルのデータを可視化 {experimentalBadge}",
"xpack.ml.formatters.metricChangeDescription.actualSameAsTypicalDescription": "実際値が通常値と同じ",
Expand Down
Loading