diff --git a/public/components/getting_started/components/getting_started_collectData.tsx b/public/components/getting_started/components/getting_started_collectData.tsx index 39ecf2e85b..ed243b71c7 100644 --- a/public/components/getting_started/components/getting_started_collectData.tsx +++ b/public/components/getting_started/components/getting_started_collectData.tsx @@ -3,33 +3,34 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useEffect } from 'react'; import { EuiAccordion, - EuiPanel, - EuiText, - EuiSpacer, + EuiButton, EuiCard, + EuiCodeBlock, + EuiComboBox, EuiFlexGroup, EuiFlexItem, - EuiSelect, - EuiTabbedContent, - EuiComboBox, - EuiButton, - EuiCodeBlock, EuiLink, EuiListGroup, EuiListGroupItem, + EuiPanel, + EuiSelect, + EuiSpacer, + EuiTabbedContent, + EuiText, EuiTitle, } from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; -import otelJson from '../getting_started_artifacts/otel-services/otel-services-1.0.0.json'; import csvFileJson from '../getting_started_artifacts/csv_file/csv_file-1.0.0.json'; import golangClientJson from '../getting_started_artifacts/golang_client/golang_client-1.0.0.json'; +import otelJson from '../getting_started_artifacts/otel-services/otel-services-1.0.0.json'; import pythonJson from '../getting_started_artifacts/python_client/python_client-1.0.0.json'; // import nginxJson from '../getting_started_artifacts/nginx/nginx-1.0.0.json'; import { IntegrationCards } from './getting_started_integrationCards'; +import { uploadAssets } from './utils'; interface CollectAndShipDataProps { isOpen: boolean; @@ -269,9 +270,10 @@ export const CollectAndShipData: React.FC = ({ ))} { - setSaveMessage('Pattern created successfully'); - setTimeout(() => setSaveMessage(null), 3000); + onClick={async () => { + // setSaveMessage('Pattern created successfully'); + // setTimeout(() => setSaveMessage(null), 3000); + await uploadAssets(); }} > Create Pattern diff --git a/public/components/getting_started/components/utils.tsx b/public/components/getting_started/components/utils.tsx new file mode 100644 index 0000000000..ba11969ca6 --- /dev/null +++ b/public/components/getting_started/components/utils.tsx @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { coreRefs } from '../../../framework/core_refs'; +import { uploadBundle } from '../../integrations/components/upload_flyout'; + +export const uploadAssets = async () => { + const http = coreRefs.http; + let responeData = {}; + + try { + await http! + .get('/api/observability/gettingstarted') + .then((res: any) => { + responeData = res; + console.log(responeData); + }) + .catch((error) => { + console.error('failed to fetch file'); + }); + + const blob = new Blob([responeData.data], { type: 'application/x-ndjson' }); + const file = new File([blob], 'your-ndjson-file.ndjson'); + + const error = await uploadBundle(file); + if (error) { + console.error(error.message); + } else { + console.log('Bundle uploaded successfully'); + } + // const result = await responeData.json(); + } catch (err) { + console.error(err.message); + } +}; diff --git a/public/components/integrations/components/upload_flyout.tsx b/public/components/integrations/components/upload_flyout.tsx index e9d3a15da5..beb5a4d591 100644 --- a/public/components/integrations/components/upload_flyout.tsx +++ b/public/components/integrations/components/upload_flyout.tsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState } from 'react'; import { EuiButton, EuiFilePicker, @@ -16,11 +15,11 @@ import { EuiForm, EuiFormRow, } from '@elastic/eui'; -import { useEffect } from 'react'; -import { coreRefs } from '../../../../public/framework/core_refs'; +import React, { useEffect, useState } from 'react'; import { useToast } from '../../../../public/components/common/toast'; +import { coreRefs } from '../../../../public/framework/core_refs'; -const uploadBundle = async (bundle: File | null): Promise => { +export const uploadBundle = async (bundle: File | null): Promise => { if (!bundle) { return new Error('No bundle selected'); } diff --git a/server/routes/getting_started/getting_started_router.ts b/server/routes/getting_started/getting_started_router.ts new file mode 100644 index 0000000000..c0d7f32652 --- /dev/null +++ b/server/routes/getting_started/getting_started_router.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import fs from 'fs'; +import path from 'path'; +import { + IOpenSearchDashboardsResponse, + IRouter, + ResponseError, +} from '../../../../../src/core/server'; + +export function registerGettingStartedRoutes(router: IRouter) { + // Fetch all the custom panels available + router.get( + { + path: `/api/observability/gettingstarted`, + validate: {}, + }, + async ( + context, + request, + response + ): Promise> => { + try { + const filePath = path.join(__dirname, 'tutorial-1.0.0.ndjson'); + const fileData = await fs.promises.readFile(filePath, 'utf8'); + return response.ok({ + body: { + data: fileData, + }, + }); + } catch (error) { + console.error('Issue in fetching NDJSON file:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); +} diff --git a/server/routes/getting_started/tutorial-1.0.0.ndjson b/server/routes/getting_started/tutorial-1.0.0.ndjson new file mode 100644 index 0000000000..335eb77c43 --- /dev/null +++ b/server/routes/getting_started/tutorial-1.0.0.ndjson @@ -0,0 +1,4 @@ +{"attributes":{"description":"Python client application logs tutorial for ingesting applicative log data and building a dashboard ","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"title":"python client getting started","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"python client getting started\",\"type\":\"markdown\",\"aggs\":[],\"params\":{\"fontSize\":12,\"openLinksInNewTab\":false,\"markdown\":\"# Python Client Integration\\nThe next integration contains instructions and tutorial of setting up python opensearch client and logging applicative telemetry into opensearch.\\n\\n## Logging with OpenSearch in Python: \\n\\nLogging is an important aspect of software development,OpenSearch, is a robust and scalable solution, stands out for storing and analyzing logs efficiently.\\nThis guide walks you through integrating OpenSearch as a storage and analytics into component used in your Python project for effective logging.\\n\\n### Install Python Libraries\\nInstall the OpenSearch Python client to interact with OpenSearch:\\n\\n```bash\\npip install opensearch-py\\n```\\nSee additional documentation [here](https://opensearch.org/docs/latest/clients/python-low-level/).\\n\\n## Integrating OpenSearch with Your Python Project\\n\\n### Step 1: Import the OpenSearch Client\\nIn your Python project, import the necessary module:\\n\\n```python\\nfrom opensearchpy import OpenSearch\\n```\\n\\n### Step 2: Establish a Connection\\nCreate a connection to your OpenSearch cluster:\\n\\n```python\\nos = OpenSearch([{'host': 'opensearch_host', 'port': 9200}])\\n```\\n\\n### Step 3: Indexing Logs\\nIndex your logs into OpenSearch:\\n\\n```python\\nlog_entry = {\\n 'timestamp': '2024-02-05T12:00:00',\\n 'level': 'info',\\n 'message': 'Your log message here.',\\n 'source': 'your_python_project'\\n}\\n\\nindex_name = 'index_name'\\n\\nos.index(index=index_name, body=log_entry)\\n```\\n\\n### Step 4: Querying Logs\\nRetrieve logs using OpenSearch's powerful search capabilities:\\n\\n```python\\nquery = {\\n 'query': {\\n 'match': {'level': 'error'}\\n }\\n}\\n\\nresult = os.search(index=index_name, body=query)\\nprint(result)\\n```\\n\\n## Best Practices for Effective Logging\\n\\n1. **Descriptive Log Messages**: Include clear and detailed information.\\n2. **Appropriate Log Levels**: Use different levels (INFO, DEBUG, ERROR) to categorize log messages.\\n3. **Timestamps**: Always include timestamps for chronological analysis.\\n4. **Contextual Information**: Add details like module, function, or user IDs.\\n5. **Avoid Redundant Logging**: Balance between sufficient information and avoiding overload.\\n6. **Secure Sensitive Information**: Do not log sensitive data in plain text.\\n7. **Structured Logging**: Use JSON for consistent log formats.\\n\\n## Advanced Features of OpenSearch\\n\\n- **Index Patterns and Mappings**: Optimize log data structure for better analysis and retrieval.\\n- **Visualization with Dashboards**: Create interactive dashboards for real-time log insights.\\n\\n# How to build an Application Monitor Dashboard\\nBased on the ingested logs, lets review the process of generating an informative monitor dashboard for the applicative logs:\\n\\n## Step-by-Step Tutorial: Creating an OpenSearch Dashboard for Application Logs\\n\\n### 1. Log in to opensearch dashboards\\n- Navigate to OpenSearch Dashboards.\\n- Log in and verify the logs index was created and contains logs data\\n- Go to Discover tab, select the index name and view the data\\n\\n### 2. Create an Index Pattern\\n- Go to 'Management' > 'Index Patterns'.\\n- Click 'Create Index Pattern' and enter the pattern (e.g., logs-*).\\n- Select the timestamp field (e.g., @timestamp) for time-based data.\\n- Save the index pattern.\\n\\n### 3. Build Log Queries\\n- Go to the 'Discover' tab.\\n- Use the search bar to filter logs, e.g., `log_level:ERROR` to find all error logs.\\n- For advanced filtering, utilize the Dashboard Query Language (DQL).\\n\\n### 4. Save Your Query\\n- After refining your query, save it by clicking on the 'Save' button in the 'Discover' tab.\\n- Name your saved query for easy reference.\\n\\n### 5. Create Visualizations\\n- Go to 'Visualize' > 'Create Visualization'.\\n- Select the type of visualization you want to create (e.g., bar chart, pie chart).\\n- Choose your saved query as the data source.\\n\\n### 6. Add Buckets for Data Aggregation\\n- In the visualization settings, add buckets to aggregate your data. For example:\\n - Use 'Date Histogram' for the X-axis to display logs over time.\\n - Add other metrics or aggregations as needed.\\n\\n### 7. Split Series for Detailed Insights\\n- Add another bucket to split data by specific fields, such as `service.name` or `host.name`.\\n- This will allow you to see log distributions across different services or hosts.\\n\\n### 8. Customize Visualization\\n- Customize the visualization with labels, colors, and other settings to make it more informative and visually appealing.\\n\\n### 9. Save and Add to Dashboard\\n- Save the visualization with a descriptive name.\\n- Navigate to the 'Dashboard' tab and create a new dashboard.\\n- Add your saved visualizations to the dashboard by selecting them from the list.\\n\\n### 10. Finalize and Share\\n- Arrange the visualizations on the dashboard as desired.\\n- Save the dashboard with a meaningful name.\\n- Share the dashboard with your team by generating a shareable link or embedding it in your application.\\n\\n### Tips for Effective Dashboards\\n- Use different types of visualizations to present various aspects of your log data.\\n- Regularly update the time filter to ensure you're viewing the most recent logs.\\n- Take advantage of OpenSearch Dashboards' interactive features, such as drill-downs and filters, for deeper analysis.\\n\\n\"}}"},"id":"8d8e5860-3fc8-11ef-a406-af6eb3c84d77","migrationVersion":{"visualization":"7.10.0"},"references":[],"type":"visualization","updated_at":"2024-07-11T21:00:07.270Z","version":"WzM5LDVd"} +{"attributes":{"description":"Python client application logs tutorial for ingesting applicative log data and building a dashboard ","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"language\":\"kuery\",\"query\":\"\"},\"filter\":[]}"},"optionsJSON":"{\"hidePanelTitles\":false,\"useMargins\":true}","panelsJSON":"[{\"version\":\"2.15.0\",\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"03db4608-6c38-4ea1-b56b-00981b5c0956\"},\"panelIndex\":\"03db4608-6c38-4ea1-b56b-00981b5c0956\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]","timeRestore":false,"title":"Python client application logs tutorial dashboard","version":1},"id":"python-getting-started-tutorial-1.0.0","migrationVersion":{"dashboard":"7.9.3"},"references":[{"id":"8d8e5860-3fc8-11ef-a406-af6eb3c84d77","name":"panel_0","type":"visualization"}],"type":"dashboard","updated_at":"2024-07-11T21:00:22.748Z","version":"WzQwLDVd"} +{"attributes":{"fields":"[{\"count\":0,\"name\":\"_id\",\"type\":\"string\",\"esTypes\":[\"_id\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_index\",\"type\":\"string\",\"esTypes\":[\"_index\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_score\",\"type\":\"number\",\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_source\",\"type\":\"_source\",\"esTypes\":[\"_source\"],\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"_type\",\"type\":\"string\",\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"error_code\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"function\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"level\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"message\",\"type\":\"string\",\"esTypes\":[\"text\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"count\":0,\"name\":\"module\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"source\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"timestamp\",\"type\":\"date\",\"esTypes\":[\"date\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"count\":0,\"name\":\"user_id\",\"type\":\"string\",\"esTypes\":[\"keyword\"],\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","timeFieldName":"timestamp","title":"applicative_logs*"},"id":"15746330-447b-11ef-99f2-2b48f7e65060","migrationVersion":{"index-pattern":"7.6.0"},"references":[],"type":"index-pattern","updated_at":"2024-07-17T20:28:10.338Z","version":"WzUsMV0="} +{"exportedCount":3,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/server/routes/index.ts b/server/routes/index.ts index d8a6952332..1627d6f0a3 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -15,6 +15,7 @@ import { registerDataConnectionsRoute } from './data_connections/data_connection import { registerDatasourcesRoute } from './datasources/datasources_router'; import { registerDslRoute } from './dsl'; import { registerEventAnalyticsRouter } from './event_analytics/event_analytics_router'; +import { registerGettingStartedRoutes } from './getting_started/getting_started_router'; import { registerIntegrationsRoute } from './integrations/integrations_router'; import { registerMetricsRoute } from './metrics/metrics_rounter'; import { registerNoteRoute } from './notebooks/noteRouter'; @@ -56,4 +57,5 @@ export function setupRoutes({ registerDataConnectionsRoute(router, dataSourceEnabled); registerDatasourcesRoute(router, dataSourceEnabled); registerQueryAssistRoutes(router); + registerGettingStartedRoutes(router); }