Dashboards & Visualizations

How to use Splunk UI/dashboard in external app?

snigam78
Explorer

we are currently exploring splunkjs for rendering data in our custom app. we are able to authenticate and display charts based on searches directly from webapp but having difficulty in integrating with react app as its not component based.

we saw the new Splunk ui/dashboard studio with many react components e.g. splunk/react-ui ,splunk-visualizations

we think we can use this react components in our external webapp butwe are not able to see any authentication mechanism in these react components.

how can we use these react components in external app which goes against splunk enterprise does authentication fires searches and displays charts.

Thanks in advance.

 

Labels (3)

ryanoconnor
Builder

This is a great question @snigam78 and something my team is currently interested in providing examples for. Would love to hear more about your use case if you have time.

We do have a couple of packages available on https://splunkui.splunk.com that I think are helpful. Here is some javascript that utilizes @splunk/splunk-utils and the @splunk/visualizations package to query Splunk from an external location, pull back some data, and populate a single value, and a column chart. 

This example allows allows you to execute post-process searches, and dynamically add new visualizations to your page. 

 

 

 

 

 

 

 

import './App.css';
import { useState, useEffect, useCallback } from 'react';
import { presets, formInputTypes } from './constants';

//@splunk/visualizations imports
//These are visualizations we are using for this demo
import SingleValue from '@splunk/visualizations/SingleValue';
import Column from '@splunk/visualizations/Column';

//@splunk/react-ui imports.
//These are what give us components that look and feel like Splunk.
import Link from '@splunk/react-ui/Link';
import List from '@splunk/react-ui/List';
import P from '@splunk/react-ui/Paragraph';
import Button from '@splunk/react-ui/Button';
import WaitSpinner from '@splunk/react-ui/WaitSpinner';
import Heading from '@splunk/react-ui/Heading';
import Switch from '@splunk/react-ui/Switch';

//@splunk/react-search imports.
//These are what give us a search bar and time picker
import SearchBar from '@splunk/react-search/components/Bar';
import Input from '@splunk/react-search/components/Input';

//@splunk/splunk-utils imports.
//This is what is used to create search jobs
import { createSearchJob, getData } from '@splunk/splunk-utils/search';

//Custom Components
import LoginComponent from './components/LoginComponent';

function App() {
    //State variables for communication with Splunkd

    const queryParams = new URLSearchParams(window.location.search);

    const [sessionKey, setSessionKey] = useState('<Token>');
    const [username, setUsername] = useState(queryParams.get('username'));
    const [password, setPassword] = useState(queryParams.get('password'));
    const [serverURL, setServerURL] = useState(queryParams.get('serverURL'));

    const headers = {
headers: {
    Authorization: `Splunk ${sessionKey}`,
},
    };

    /* Second Visualization Variables */
    //Sid for Column Chart
    const [columnSid, setColumnSid] = useState();
    //Search for Column Chart
    const [splunkSearchColumn, setSplunkSearchColumn] = useState(
'search index=_* | stats count by sourcetype | eval count=random()%200 | fields sourcetype count'
    );
    const [splunkSearchColumnEarliest, setSplunkSearchColumnEarliest] = useState('-24h');
    const [splunkSearchColumnLatest, setSplunkSearchColumnLatest] = useState('now');

    const [columnSearching, setColumnSearching] = useState(false);

    //Fields for Column Chart
    const [columnSearchResultsFields, setColumnSearchResultsFields] = useState();
    //Columns for Column Chart
    const [columnSearchResultsColumns, setColumnSearchResultsColumns] = useState();
    //Seconds to Complete for Column Chart
    const [columnSecondsToComplete, setColumnSecondsToComplete] = useState();
    const [columnSearchOptions, setColumnSearchOptions] = useState({
earliest: splunkSearchColumnEarliest,
latest: splunkSearchColumnLatest,
search: splunkSearchColumn,
timePickerPresets: presets,
timePickerFormInputTypes: formInputTypes,
timePickerAdvancedInputTypes: [],
    });
    const [columnSearchObj, setColumnSearchObj] = useState({
search: '',
earliest: '',
latest: '',
    });
    const [columnAppendPostProcess, setColumnAppendPostProcess] = useState(false);
    const [columnViz, setColumnViz] = useState([]);

    /* Second Visualization Post Process Variables */

    const [splunkSearchColumnPostProcess, setSplunkSearchColumnPostProcess] = useState(
'| search sourcetype="splunk*" OR sourcetype="*scheduler*" | sort 0 - count'
    );

    const handleColumnAppendPostProcessClick = useCallback(() => {
setColumnAppendPostProcess((current) => !current);
    }, []);

    const columnPostProcessBar = (
<>
    <div>
<div style={{ float: 'left' }}>
    <Switch
value={false}
onClick={handleColumnAppendPostProcessClick}
selected={columnAppendPostProcess}
appearance="toggle"
error={!columnAppendPostProcess}
    ></Switch>
</div>
<div>
    <Heading level={4} style={{ paddingLeft: '40px', paddingTop: '10px' }}>
{columnAppendPostProcess
    ? '     Append Visualization'
    : '     Update Existing'}
    </Heading>
</div>
    </div>
    <Input
value={splunkSearchColumnPostProcess}
onChange={(e, value) =>
    handlePostProcessChange(e, value, setSplunkSearchColumnPostProcess)
}
onEnter={() =>
    handleEventTrigger(
columnSid,
splunkSearchColumnPostProcess,
setColumnSearchResultsFields,
setColumnSearchResultsColumns
    )
}
    />
</>
    );

    //Sid for Single Value
    const [singleValueSid, setSingleValueSid] = useState();
    //Search for Single Value
    const [splunkSearchSingleValue, setSplunkSearchSingleValue] = useState(
'search index=_internal | stats count by sourcetype'
    );
    const [splunkSearchSingleValueEarliest, setSplunkSearchSingleValueEarliest] = useState('-24h');
    const [splunkSearchSingleValueLatest, setSplunkSearchSingleValueLatest] = useState('now');

    const [singleValueSearching, setSingleValueSearching] = useState(false);

    //Fields for Single Value
    const [singleValueSearchResultsFields, setSingleValueSearchResultsFields] = useState();
    //Columns for Single Value
    const [singleValueSearchResultsColumns, setSingleValueSearchResultsColumns] = useState();
    //Seconds to Complete for Single Value
    const [singleValueSeondsToComplete, setSingleValueSecondsToComplete] = useState();

    const [singleValueSearchOptions, setSingleValueSearchOptions] = useState({
earliest: splunkSearchSingleValueEarliest,
latest: splunkSearchSingleValueLatest,
search: splunkSearchSingleValue,
timePickerPresets: presets,
timePickerFormInputTypes: formInputTypes,
timePickerAdvancedInputTypes: [],
    });
    const [singleValueSearchObj, setSingleValueSearchObj] = useState({
search: '',
earliest: '',
latest: '',
    });
    const [singleValueAppendPostProcess, setSingleValueAppendPostProcess] = useState(false);

    const [singleValueViz, setSingleValueViz] = useState([]);

    const [splunkSearchSingleValuePostProcess, setSplunkSearchSingleValuePostProcess] = useState(
'| search sourcetype="splunkd"'
    );

    const handleSingleValueAppendPostProcessClick = () => {
setSingleValueAppendPostProcess(!singleValueAppendPostProcess);
    };

    const singleValuePostProcessBar = (
<>
    <div>
<div style={{ float: 'left' }}>
    <Switch
onClick={handleSingleValueAppendPostProcessClick}
selected={singleValueAppendPostProcess}
appearance="toggle"
error={!singleValueAppendPostProcess}
selectedLabel="Append Visualization"
unselectedLabel="Update Existing Visualization"
    ></Switch>
</div>

<div>
    <Heading level={4} style={{ paddingLeft: '40px', paddingTop: '10px' }}>
{singleValueAppendPostProcess
    ? '     Append Visualization'
    : '     Update Existing'}
    </Heading>
</div>
    </div>

    <Input
value={splunkSearchSingleValuePostProcess}
onChange={(e, value) =>
    handlePostProcessChange(e, value, setSplunkSearchSingleValuePostProcess)
}
onEnter={() =>
    handleEventTrigger(
singleValueSid,
splunkSearchSingleValuePostProcess,
setSingleValueSearchResultsFields,
setSingleValueSearchResultsColumns
    )
}
    />
</>
    );

    //Timer for Search length
    const timer = (ms) => new Promise((res) => setTimeout(res, ms));
    async function load(sidJob, completeFunc, fieldsFunc, columnsFunc, setSearchingBool, type) {
var completeSeconds = 0;
for (var i = 0; i < 30; i++) {
    fetchData(sidJob, fieldsFunc, columnsFunc, type)
.then((data) => data)
.then((sidJob) => {
    if (sidJob) {
completeSeconds = completeSeconds + 1;
setSearchingBool(false);
completeFunc(completeSeconds);
    }
});
    if (!completeSeconds) {
await timer(1000);
    } else {
break;
    }
}
    }

    //Function for Clicking the Post Process Search Button
    async function handlePostProcessClick(
locaPostProcessSid,
postProcessSearch,
setFields,
setColumns,
appendBool,
type
    ) {
postProcess(locaPostProcessSid, postProcessSearch, setFields, setColumns, appendBool, type);
    }

    //Function for Updating the Post Process Search
    function handlePostProcessChange(e, value, setPostProcess) {
setPostProcess(value.value);
    }

    const createJob = async (search, earliest, latest) => {
const n = createSearchJob(
    {
search: search,
earliest_time: earliest,
latest_time: latest,
    },
    {},
    { splunkdPath: serverURL, app: 'search', owner: username },
    headers
)
    .then((response) => response)
    .then((data) => data.sid);
return n;
    };

    const fetchData = async (sidJob, fieldsFunc, columnsFunc, type) => {
const n = await getData(
    sidJob,
    'results',
    { output_mode: 'json_cols' },
    { splunkdPath: serverURL, app: 'search', owner: username },
    headers
)
    .then((response) => response)
    .then((data) => {
if (data) {
    fieldsFunc(data.fields);
    columnsFunc(data.columns);
    
    if (type == 'SingleValue') {
setSingleValueViz([
    <SingleValue
options={{
    majorColor: '#008000',
    sparklineDisplay: 'off',
    trendDisplay: 'off',
}}
dataSources={{
    primary: {
data: {
    fields: data.fields,
    columns: data.columns,
},
meta: {},
    },
}}
    />,
]);
    }
    if (type == 'Column') {
setColumnViz([
    <Column
options={{}}
dataSources={{
    primary: {
data: {
    fields: data.fields,
    columns: data.columns,
},
meta: {},
    },
}}
    />,
]);
    }
    return data;
}
    });
return n;
    };

    const postProcess = async (sidJob, postProcess, fieldsFunc, columnsFunc, appendBool, type) => {
const n = await getData(
    sidJob,
    'results',
    { output_mode: 'json_cols', search: postProcess },
    { splunkdPath: serverURL, app: 'search', owner: username },
    headers
)
    .then((response) => response)
    .then((data) => {
if (data) {
    fieldsFunc(data.fields);
    columnsFunc(data.columns);
    if (appendBool) {
if (type == 'SingleValue') {
    setSingleValueViz([
...singleValueViz,
<SingleValue
    options={{
majorColor: '#008000',
sparklineDisplay: 'off',
trendDisplay: 'off',
    }}
    dataSources={{
primary: {
    data: {
columns: data.columns,
fields: data.fields,
    },
    meta: {},
},
    }}
/>,
    ]);
}
if (type == 'Column') {
    setColumnViz([
...columnViz,
<Column
    options={{}}
    dataSources={{
primary: {
    data: {
columns: data.columns,
fields: data.fields,
    },
    meta: {},
},
    }}
/>,
    ]);
}
    } else {
if (type == 'SingleValue') {
    setSingleValueViz([
<SingleValue
    options={{
majorColor: '#008000',
sparklineDisplay: 'off',
trendDisplay: 'off',
    }}
    dataSources={{
primary: {
    data: {
columns: data.columns,
fields: data.fields,
    },
    meta: {},
},
    }}
/>,
    ]);
}

if (type == 'Column') {
    setColumnViz([
<Column
    options={{}}
    dataSources={{
primary: {
    data: {
columns: data.columns,
fields: data.fields,
    },
    meta: {},
},
    }}
/>,
    ]);
}
    }
    return data;
}
    });
return n;
    };

    const handleOptionsChange = async (option, setSearchOptions, searchOptions) => {
setSearchOptions({
    ...searchOptions,
    ...option,
});
    };

    /**
     * Invoked when the user hits enter or click on the search button
     */
    const handleEventTrigger = async (
eventType,
Sid,
setSidFunc,
setSearchObjFunction,
searchObj,
setSecondsToComplete,
setSearchResultsFields,
setSearchResultsColumns,
setSearchingBool,
setOptionsFunc,
searchOptions,
type
    ) => {
setSearchObjFunction({
    search: searchOptions.search,
    earliest: searchOptions.earliest,
    latest: searchOptions.latest,
});
switch (eventType) {
    case 'submit':
setSearchingBool(true);
createJob(searchOptions.search, searchOptions.earliest, searchOptions.latest)
    .then((data) => data)
    .then((sidJob) => {
setSidFunc(sidJob);
load(
    sidJob,
    setSecondsToComplete,
    setSearchResultsFields,
    setSearchResultsColumns,
    setSearchingBool,
    type
);
    });

break;
    case 'escape':
this.handleOptionsChange({ search: '' }, setOptionsFunc, searchOptions);
break;
    default:
break;
}
    };

    const wordBreakStyle = { overflowWrap: 'break-word', margin: '10px' };
    return (
<div className="App">
    <header className="App-header">
<Heading level={1}>@splunk/splunk-utils Example app</Heading>
<P>
    This app will show you how to query Splunk from a remote webapp using our Splunk
    UI Toolkit in React. It uses a couple of packages listed below:{' '}
</P>
<List>
    <List.Item>
<Link to="https://www.npmjs.com/package/@splunk/splunk-utils">
    @splunk/splunk-utils
</Link>
    </List.Item>
    <ul>
<li>
    <Link to="https://splunkui.splunkeng.com/Packages/splunk-utils">
Documentation
    </Link>
</li>
    </ul>
    <List.Item>
<Link to="https://www.npmjs.com/package/@splunk/visualizations">
    @splunk/visualizations
</Link>
    </List.Item>
    <ul>
<li>
    <Link to="https://splunkui.splunkeng.com/Packages/visualizations">
Documentation
    </Link>
</li>
    </ul>
    <List.Item>
<Link to="https://www.npmjs.com/package/@splunk/react-ui">
    @splunk/react-ui
</Link>
    </List.Item>
    <ul>
<li>
    <Link to="https://splunkui.splunkeng.com/Packages/react-ui">
Documentation
    </Link>
</li>
    </ul>
</List>
{sessionKey == '<Token>' ? (
    <>
<Heading level={2}>Setup Instructions</Heading>
<P>
    Note: You may need to complete a step for this app to work with your
    Splunk Environment. Details below:
</P>
<List>
    <List.Item>
You'll need to configure CORS on your Splunk Environment.
Instructions can be found{' '}
<Link to="https://dev.splunk.com/enterprise/docs/developapps/visualizedata/usesplunkjsstack/communicatesplunkserver/">
    here
</Link>
    </List.Item>
    <List.Item>
You'll need to have a trusted certificate for the Splunk management
port. If you don't have a valid certificate, you can always visit
the URL for the management port of your Splunk environment, and
trust the certificate manually with your browser.
    </List.Item>
</List>
    </>
) : (
    <></>
)}

{sessionKey == '<Token>' ? (
    <>
<LoginComponent
    username={username}
    setUsername={setUsername}
    password={password}
    setPassword={setPassword}
    serverURL={serverURL}
    setServerURL={setServerURL}
    sessionKey={sessionKey}
    setSessionKey={setSessionKey}
></LoginComponent>
    </>
) : (
    <div style={{ width: '100%' }}>
<div style={{ float: 'left', width: '47%', padding: '10px' }}>
    <Heading style={wordBreakStyle} level={3}>
This is a Single Value that is populated by the following search:{' '}
    </Heading>
    <div style={{ padding: '10px' }}>
<SearchBar
    options={singleValueSearchOptions}
    onOptionsChange={(options) =>
handleOptionsChange(
    options,
    setSingleValueSearchOptions,
    singleValueSearchOptions
)
    }
    onEventTrigger={(eventType) =>
handleEventTrigger(
    eventType,
    singleValueSid,
    setSingleValueSid,
    setSingleValueSearchObj,
    singleValueSearchObj,
    setSingleValueSecondsToComplete,
    setSingleValueSearchResultsFields,
    setSingleValueSearchResultsColumns,
    setSingleValueSearching,
    setSingleValueSearchOptions,
    singleValueSearchOptions,
    'SingleValue'
)
    }
/>
    </div>
    {singleValueSearching ? <WaitSpinner size="medium" /> : <></>}

    {singleValueSeondsToComplete ? (
<>
    {singleValueViz.map((key, value) => {
return key;
    })}
    <Heading style={wordBreakStyle} level={3}>
Clicking this button will execute the following post-process
search:{' '}
    </Heading>

    {singleValuePostProcessBar}

    <Button
label="Execute Post-process"
appearance="primary"
onClick={() =>
    handlePostProcessClick(
singleValueSid,
splunkSearchSingleValuePostProcess,
setSingleValueSearchResultsFields,
setSingleValueSearchResultsColumns,
singleValueAppendPostProcess,
'SingleValue'
    )
}
    />
    <P style={wordBreakStyle}>
Search: {singleValueSearchOptions.search}
    </P>
    <P style={wordBreakStyle}>{'Splunk SID: ' + singleValueSid}</P>
    <P style={wordBreakStyle}>
{'Seconds to Complete: ' +
    JSON.stringify(singleValueSeondsToComplete)}
    </P>
    <P style={wordBreakStyle}>
{'Splunk Results - Fields: ' +
    JSON.stringify(singleValueSearchResultsFields)}
    </P>
    <P style={wordBreakStyle}>
{'Splunk Results - Columns: ' +
    JSON.stringify(singleValueSearchResultsColumns)}
    </P>
</>
    ) : (
<></>
    )}
</div>

<div style={{ float: 'right', width: '47%', padding: '10px' }}>
    <Heading style={wordBreakStyle} level={3}>
This is a Column Chart that is populated by the following search:{' '}
    </Heading>
    <div style={{ padding: '10px' }}>
<SearchBar
    options={columnSearchOptions}
    onOptionsChange={(options) =>
handleOptionsChange(
    options,
    setColumnSearchOptions,
    columnSearchOptions
)
    }
    onEventTrigger={(eventType) =>
handleEventTrigger(
    eventType,
    columnSid,
    setColumnSid,
    setColumnSearchObj,
    columnSearchObj,
    setColumnSecondsToComplete,
    setColumnSearchResultsFields,
    setColumnSearchResultsColumns,
    setColumnSearching,
    setColumnSearchOptions,
    columnSearchOptions,
    'Column'
)
    }
/>
    </div>
    {columnSearching ? <WaitSpinner size="medium" /> : <></>}

    {columnSecondsToComplete ? (
<>
    {columnViz.map((key, value) => {
return key;
    })}

    <Heading style={wordBreakStyle} level={3}>
Clicking this button will execute the following post-process
search:{' '}
    </Heading>

    {columnPostProcessBar}

    <Button
label="Execute Post-process"
appearance="primary"
onClick={() =>
    handlePostProcessClick(
columnSid,
splunkSearchColumnPostProcess,
setColumnSearchResultsFields,
setColumnSearchResultsColumns,
columnAppendPostProcess,
'Column'
    )
}
    />

    <P style={wordBreakStyle}>
Search: {columnSearchOptions.search}
    </P>
    <P>{'Splunk SID: ' + columnSid}</P>
    <P style={wordBreakStyle}>
{'Seconds to Complete: ' +
    JSON.stringify(columnSecondsToComplete)}
    </P>
    <P style={wordBreakStyle}>
{'Splunk Results - Fields: ' +
    JSON.stringify(columnSearchResultsFields)}
    </P>
    <P style={wordBreakStyle}>
{'Splunk Results - Columns: ' +
    JSON.stringify(columnSearchResultsColumns)}
    </P>
</>
    ) : (
<></>
    )}
</div>
    </div>
)}
    </header>
</div>
    );
}

export default App;

 

 

 

 

 

 

 

 

 

pgoldweic
Communicator

While I didn't write the original post, I hope it's okay to reply to @ryanoconnor here with a couple of follow-up questions on the code he posted. First of all, thanks so much for posting this code! Here are the questions:

1- Does the authentication (via the Authorization header) require *only* the new authentication tokens, or does it also work with session key values (retrieved via the  legacy login  REST endpoint)?

2- When writing these apps outside of Splunk, can we make use of Splunk css files similarly to what we could do with splunkjs? (in splunkjs-based apps, we're able to keep all the relevant splunk-related css files in a special static/splunkjs app folder).  These css files could then be used within the React code (similarly to how you use App.css in the example).

0 Karma

ryanoconnor
Builder

Hello! Happy to report back some news here.

 

1. This will work with a sessionKey that can be obtained from a REST call to the /services/auth/login endpoint documented here (I've updated the code above). 

 

2. I believe the answer is yes here. But I might need to dig in more to your use case to see what you have. I would also recommend looking at our Splunk UI components and also our @splunk/themes package, as that may solve this more easily for you: https://splunkui.splunk.com/Packages/themes/Overview

 

Hope this helps!

 

EDIT: I am keeping the code in the comment above. As pasting multiple versions in here is getting unwieldy. 

 

 

pgoldweic
Communicator

Thanks so much for your updated post @ryanoconnor . Would be great if you could also share two files that your code requires: ."/App.css", and also "./constants", which should help with running this sample in a real  environment.  Or, at least share the "constants" file only, since I now realize that "App.css" might be the one created automatically by create-react-app. 

 

0 Karma

ryanoconnor
Builder

No problem! And apologies for the delay on this. I do plan to hopefully open source this code which will make life easier in the future for this example. 

 

App.css

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

 

constants.js

export const formInputTypes = ['relative'];

export const presets = [
    { label: 'Today', earliest: '@d', latest: 'now' },
    { label: 'Week to date', earliest: '@w0', latest: 'now' },
    { label: 'Business week to date', earliest: '@w1', latest: 'now' },
    { label: 'Month to date', earliest: '@mon', latest: 'now' },
    { label: 'Year to date', earliest: '@y', latest: 'now' },
    { label: 'Yesterday', earliest: '-1d@d', latest: '@d' },
    { label: 'Previous week', earliest: '-7d@w0', latest: '@w0' },
    { label: 'Previous business week', earliest: '-6d@w1', latest: '-1d@w6' },
    { label: 'Previous month', earliest: '-1mon@mon', latest: '@mon' },
    { label: 'Previous year', earliest: '-1y@y', latest: '@y' },
    { label: 'Last 15 minutes', earliest: '-15m', latest: 'now' },
    { label: 'Last 60 minutes', earliest: '-60m@m', latest: 'now' },
    { label: 'Last 4 hours', earliest: '-4h@m', latest: 'now' },
    { label: 'Last 24 hours', earliest: '-24h@h', latest: 'now' },
    { label: 'Last 7 days', earliest: '-7d@h', latest: 'now' },
    { label: 'Last 30 days', earliest: '-30d@d', latest: 'now' },
    { label: 'All time', earliest: '0', latest: '' },
];

 

FYI The constants file should have been in the docs here https://splunkui.splunk.com/Packages/react-search/ but I realize it's not. I'll try to get that corrected. 

mleati
Explorer

Ryan,

Your posts (here and elsewhere) are greatly appreciated. They really help with learning Splunk UI Kit. I came across this thread while trying to learn more about splunk-utils/search. I am a little bit confused between the different options Splunk offers now for front-end web development. Your post here (https://www.splunk.com/en_us/blog/platform/splunk-ui-and-the-dashboard-framework-more-visual-control... helps understanding use cases for Dashboard Framework. I also saw a post/article (can't find it anymore) comparing use cases for Dashboard Framework vs conventional React app based on Splunk UI components (like Visualizations). The Dashboard Framework seems a little too heavy for simpler use cases. On the other hand use of individual components has its own issues (I think it does not scale well). At this point I am concentrated on the latter approach. I find it easy to use components from @splunk/react-ui. Use of components from @splunk/visualizations is not as straightforward. It requires  development of a glue code for connecting search results with visualization component (DF might be the answer but it comes with its own tradeoffs).

So far I have been using @splunk/search-job for performing the searches. This one is used in some of the examples offered with Splunk UI Kit. But then I came across @splunk/splunk-utils/search. This one seemingly offers the features similar to @splunk/search-job (with more granular control over the search job). This thread is the only place where I found an example of how to use @splunk/splunk-utils/search (and the documentation is just not sufficient for learning how to use this component). Could you elaborate on the target use cases for these two approaches?

Thanks in advance.

0 Karma

nhaq
Splunk Employee
Splunk Employee

Hello @mleati,

 

I work with @ryanoconnor as a PM for the Splunk UI Toolkit and I think I can help out with your question. Simply put, SearchJob uses Splunk Utils to complete its functionality, but by providing the search capabilities under the SearchJob package, we simplify the process for developers to run searches within Splunk Web (ie, your app is "on" Splunk). So if your app is in Splunk Web, we highly recommend that you use SearchJob, and it will be a simpler experience to run your searches that way. 

Splunk Utils on the other hand, is our "catch all" for interacting with the REST API. You can use it to store secrets, run searches, or read the KV store. The main reason why one would use Splunk Utils specifically for searching, is if they have an application outside of Splunk Web (for example, their own web app) and they want to pull Splunk data. Hope that clarifies it for you. Regarding documentation, we hope to improve the documentation for Search Job and Splunk Utils in the near future, however we do have our examples gallery, and here are a few examples that I think would help specifically to your question. 

https://github.com/splunk/SUIT-example-for-visualizations - A clear set of examples for searching within Splunk using Search Job and tying those results to visualizations

https://github.com/splunk/react_search_example - An app outside of Splunk using Splunk Utils to search against Splunk

https://github.com/splunk/SUIT-setup-page-example - An example of leveraging Splunk Utils to accomplish a common Splunk App workflow, which is to store a secret in the storage/passwords API endpoint. 

 

If you have any other questions, please reach out!

 

mleati
Explorer

Thanks for prompt reply which perfectly clarifies the issue. Since we are on this topic, I have another question. Splunk dashboards have a notion of base searches and the feature is easy to use. When developing React App (running on Splunk server) without relying on the Dashboard Framework does any of these APIs offer an easy way to reuse the results of the "base" search for a new search? The only relevant thing I was able to find  is the PostProcessManager in the legacy Splunk Web Framework (https://dev.splunk.com/enterprise/docs/developapps/visualizedata/addsearches). Is this the only option? Perhaps, simply prefixing follow up query with "| loadjob <sid>" would do the trick?

0 Karma

nhaq
Splunk Employee
Splunk Employee

Hey @mleati ,

That is a good point, if you look at the code of this example I provided:

That examples does indeed show how to do post-process searches for apps outside of Splunk. 

For apps within Splunk, the @splunk/search-job package can help you out easily, we have Post Process capability built-in.

 

Hope that helps!

Note that if you are using the Splunk UI Toolkit, searches and API calls should be done with our packages if they relate strictly to UI, so I wouldn't recommend trying to make an app with the Splunk UI toolkit and referencing the old Splunk JavaScript SDK or SplunkJS/Splunk Web Framework and mixing functionality just yet. 

pgoldweic
Communicator

Thanks so much @ryanoconnor for sharing all that information! Very useful indeed. 

0 Karma

richgalloway
SplunkTrust
SplunkTrust

Splunk Dashboard Studio is a new product that is still evolving so I suspect your use case has not yet been implemented.  Go to https://ideas.splunk.com to ask them to move it up the priority list.

---
If this reply helps you, Karma would be appreciated.
Get Updates on the Splunk Community!

Continuing Innovation & New Integrations Unlock Full Stack Observability For Your ...

You’ve probably heard the latest about AppDynamics joining the Splunk Observability portfolio, deepening our ...

Monitoring Amazon Elastic Kubernetes Service (EKS)

As we’ve seen, integrating Kubernetes environments with Splunk Observability Cloud is a quick and easy way to ...

Cloud Platform & Enterprise: Classic Dashboard Export Feature Deprecation

As of Splunk Cloud Platform 9.3.2408 and Splunk Enterprise 9.4, classic dashboard export features are now ...