Add_Graph_for Splunk

master
admingit 3 years ago
parent 94dd1c26cf
commit 2e60ed0049

@ -0,0 +1,31 @@
# Contributing Guidelines
Thank you for considering spending your time contributing to the Splunk 3D Graph Network Topology Visualization. :rocket:
Whether you're interested in bug-hunting, documentation, or creating entirely new features, this document will help and guide you through the process.
## Issues & Bug Reports
If you're seeing some unexpected behavior with this project, please create an [issue](https://github.com/splunk/splunk-3D-graph-network-topology-viz/issues) on GitHub selecting the opportune template and providing requested information.
## Pull Requests
We :heart: to see your fixes via pull requests!
To create a pull request:
* [Fork](https://guides.github.com/activities/forking/) the project
* Create a branch for the issue
* Make your changes on your branch
* Thoroughly test your changes
* Open a [pull request](https://github.com/splunk/splunk-3D-graph-network-topology-viz/pulls)
Remember:
* **Address an issue per branch**
## Semi-Automated Release
A [GitHub Action](https://github.com/splunk/splunk-3D-graph-network-topology-viz/actions/workflows/manual-release.yml) is provided to:
* Bump the app version
* Create a release
This action can be **manually triggered** by clicking on _Actions / Manual Release / Run Workflow_ and by providing:
* **Bump part** - Either major, minor or patch
* (Optional) **Changelog notes** - By default all commit messages beginning from the last release are included
> **NOTE** Action available to all users with `Write` role at least

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 Splunk Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,99 @@
# Splunk 3D Graph Network Topology Visualization
![Custom badge](https://img.shields.io/endpoint?label=SplunkBase%20Downloads&url=https%3A%2F%2Fsplunkbasebadge.livehybrid.com%2Fv1%2Fdownloads%2F4611%2F)
[![Actions Status: ci](https://github.com/splunk/splunk-3D-graph-network-topology-viz/actions/workflows/ci.yml/badge.svg)](https://github.com/splunk/splunk-3D-graph-network-topology-viz/actions?query=workflow%3A"CI")
[![Latest release (latest by date)](https://img.shields.io/github/v/release/splunk/splunk-3D-graph-network-topology-viz?label=Latest%20Release)](https://github.com/splunk/splunk-3D-graph-network-topology-viz/releases)
[![License](https://img.shields.io/github/license/splunk/splunk-3D-graph-network-topology-viz)](LICENSE)
Plot relationships between objects with force directed graph based on ThreeJS/WebGL.
More information around use cases on the following Splunk blogs:
- [Chasing a Hidden Gem: Graph Analytics with Splunks Machine Learning Toolkit](https://www.splunk.com/en_us/blog/machine-learning/chasing-a-hidden-gem-graph-analytics-with-splunk-s-machine-learning-toolkit.html)
- Understanding and baselining network behaviour [[part 1](https://www.splunk.com/en_us/blog/machine-learning/understanding-and-baselining-network-behaviour-using-machine-learning-part-i.html) / [part 2](https://www.splunk.com/en_us/blog/machine-learning/understanding-and-baselining-network-behaviour-using-machine-learning-part-ii.html)]
## Installation
Please refer to [Splunk Documentation](https://docs.splunk.com/Documentation/AddOns/released/Overview/Installingadd-ons) for guidance on installing this visualization in your environment. The app needs to be installed on the SH tier.
Download is available from either [GitHub](https://github.com/splunk/splunk-3D-graph-network-topology-viz/releases) or [Splunkbase](https://splunkbase.splunk.com/app/4611/).
## Usage
`<search> | stats count by src dest [color_src] [color_dest] [edge_color] [weight_src] [weight_dest] [edge_weigth]`
Replace `src` and `dest` with your fields to start. All other fields are optional and default values will be used if not given.
### Optional values
Used to customise nodes and edges (or links) styling.
| FieldName | Format | Description | Example |
|---------------|---------|---------------------------------------|-----------|
| `color_src` | string | Color of source node in HEX | `#00DD00` |
| `color_dest` | string | Color of destination node in HEX | `#CC00FF` |
| `edge_color` | string | Color of edge in HEX | `#12FF00` |
| `weight_src` | numeric | Sphere size of source node | `2.5` |
| `weight_dest` | numeric | Sphere size of destination node | `3` |
| `edge_weight` | numeric | Stroke weight of edge line in pixels | `2.1` |
Besides:
* Field names **must** correspond to the ones specified above to be properly handled by the visualization
* Any `edge_weight` value higher than `18` will be normalised to `18`
## Examples
### Lookup tables
* Add a lookup table defining these additional values to your Splunk instance. An example below:
```
$~ cat <your_lookup_table>.csv
source,color,weight
A,#010101,50
B,#ff0101,10
...
```
* Execute your SPL
`<search> | stats count by src dest | lookup <your_lookup_table> source AS src | lookup <your_lookup_table> source AS dest OUTPUTNEW color AS color_dest, weight AS weight_dest`
### Simple SPL
* Execute your SPL
`<search> | stats count as edge_weight by src dest | eval color_src="#cc0000", color_dest="#00ff00", weight_src=3 | eval edge_color=if(edge_weight < 18, "#0000cc","")`
## Graph Algorithm Examples
Four dashboards are provided to show graph algorithms in action using NetworkX. Select them by clicking on `Graph Example Dashboards` dropdown in the app navigation bar.
### Requirements
Make sure you have the following Splunk apps installed in your instance to correctly visualize integrated dashboards.
* [Splunk's Machine Learning Toolkit (MLTK)](https://splunkbase.splunk.com/app/2890)
* [Python for Scientific Computing Libraries 2.0](https://splunkbase.splunk.com/app/2882/) or later
> Give **global** permissions to MLTK app if not already done
## Hardware Acceleration in Browsers
All modern browsers shall have hardware acceleration turned on by default in order to increase your browser performance and free up CPU by leaving the GPU (Graphics Processing Unit) handling graphical intensive operations.
### Chrome
The best way to check whether hardware acceleration is turned on is to type `chrome://gpu` into the address bar at the top of the browser.
A whole bunch of results will be returned but we're interested on the section titled _Graphics Feature Status_. Please make sure "Hardware accelerated" is turned on entry WebGL (among multiple others).
To enable hardware acceleration:
* type `chrome://settings` in the address bar,
* scroll to the very bottom of that page and expand the _Advanced_ link
* scroll down till reaching the section _System_ and enable the option "Use hardware acceleration when available"
* restart the browser if requested
### Firefox
To enable hardware acceleration:
* type `about:config` in the address bar
* search for `layers.acceleration.force-enabled` and double click on it to turn the value to `true`
* restart the browser
### Other browsers
For other browsers, please refer to their specific documentation on the matter.
## Contributing
If you would like to contribute to the visualization, please have a look at our [Contribution Guide](CONTRIBUTING.md)
## LICENSE
Splunk 3D Graph Network Topology Visualization is licensed under the Apache License 2.0. Details can be found in the file [LICENSE](LICENSE).

@ -0,0 +1,6 @@
[<stanza name>]
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.enable3D = <float>
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.showAnimationBar = <float>
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.showLinkArrows = <float>
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.dagMode = <string>
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.cameraController = <string>

@ -0,0 +1,57 @@
{
"schemaVersion": "2.0.0",
"info": {
"title": "3D Graph Network Topology Viz",
"id": {
"group": null,
"name": "splunk-3D-graph-network-topology-viz",
"version": "1.3.2"
},
"author": [
{
"name": "Erica Pescio, Philipp Drieger, Greg Ainslie-Malik",
"email": null,
"company": null
}
],
"releaseDate": null,
"description": "Graph Algorithms examples and Custom Visualization to plot relationships between objects with force directed graph based on ThreeJS/WebGL.",
"classification": {
"intendedAudience": null,
"categories": [],
"developmentStatus": null
},
"commonInformationModels": null,
"license": {
"name": null,
"text": null,
"uri": null
},
"privacyPolicy": {
"name": null,
"text": null,
"uri": null
},
"releaseNotes": {
"name": null,
"text": "./README.md",
"uri": null
}
},
"dependencies": {
"Splunk_ML_Toolkit": {
"version": "*",
"optional": true
}
},
"tasks": null,
"inputGroups": null,
"incompatibleApps": null,
"platformRequirements": null,
"supportedDeployments": [
"*"
],
"targetWorkloads": [
"_search_heads"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

@ -0,0 +1,52 @@
div.ga_framework_intro {
padding-left: 10px;
padding-top: 30px;
padding-right: 200px;
}
div.ga_framework_info {
padding-left: 10px;
}
div.ga_framework_inputdata {
padding-left: 10px;
padding-bottom: 10px;
}
div.ga_general_info {
margin-top: 10px;
display: inline-flex;
padding-left: 50px;
}
div.ga_general_info .pull-left {
padding-top: 10px;
}
div.ga_general_info .pull-right {
padding-left: 50px;
}
i.large {
font-size: -webkit-xxx-large;
}
#bitcoin {
margin-left: 10px;
margin-right: 10px;
}
#tb_centralitymeasures tr:first-of-type a:hover,
#tb_minspanningtree tr:first-of-type a:hover,
#tb_conncomponents tr:first-of-type a:hover,
#tb_communitydetection tr:first-of-type a:hover {
cursor: default;
color: #fff;
}
#tb_centralitymeasures tr:first-of-type i,
#tb_minspanningtree tr:first-of-type i,
#tb_conncomponents tr:first-of-type i,
#tb_communitydetection tr:first-of-type i {
display: none;
}

@ -0,0 +1,91 @@
require([
"jquery",
"splunkjs/mvc",
"splunkjs/mvc/searchmanager",
"splunkjs/mvc/searchbarview",
"splunkjs/mvc/searchcontrolsview",
"splunkjs/mvc/simplexml/ready!"
], function(
$,
mvc,
SearchManager,
SearchbarView,
SearchControlsView
) {
var tokens = mvc.Components.get("default");
// Create the search manager
var mysearch = new SearchManager({
id: "base",
autostart: "false",
app: "search",
preview: true,
cache: true,
status_buckets: 300,
required_field_list: "*",
search: ""
});
// Create the views
var mysearchbar = new SearchbarView ({
id: "searchbar1",
managerid: "base",
el: $("#mysearchbar1")
}).render();
var mysearchcontrols = new SearchControlsView ({
id: "searchcontrols1",
managerid: "base",
el: $("#mysearchcontrols1")
}).render();
// When the query in the searchbar changes, update the search manager
mysearchbar.on("change", function() {
mysearch.settings.unset("search");
mysearch.settings.set("search", mysearchbar.val());
// set token value with search string
var searchString = mysearchbar.val();
//Collect tokens from the dashboard
function setToken(name, value) {
defaultTokenModelun.set(name, value);
submittedTokenModelun.set(name, value);
}
function unsetToken(name) {
defaultTokenModelun.unset(name);
submittedTokenModelun.unset(name);
}
var defaultTokenModelun = mvc.Components.getInstance('default', { create: true });
var submittedTokenModelun = mvc.Components.getInstance('submitted', { create: true });
//Show the edit panel
setToken("searchString",searchString);
setToken("earliest",mysearch.settings.attributes.earliest_time);
setToken("latest",mysearch.settings.attributes.latest_time);
console.log("Eariest time: " + defaultTokenModelun.get("earliest"));
console.log("Latest time: " + defaultTokenModelun.get("latest"));
unsetToken("beforeSearch");
});
// When the timerange in the searchbar changes, update the search manager
mysearchbar.timerange.on("change", function() {
mysearch.settings.set(mysearchbar.timerange.val());
});
// actions for the populate search Buttons
$('#cidds').on("click", function (e){
mysearchbar.val("| inputlookup cidds_ip_connections.csv | search src_ip=192.168.* dest_ip=192.168.*");
});
$('#bitcoin').on("click", function (e){
mysearchbar.val("| inputlookup bitcoin_transactions.csv | head 1000 | rename user_id_from as src user_id_to as dest");
});
$('#internal').on("click", function (e){
mysearchbar.val("index=_internal | stats count by source sourcetype");
});
});

@ -0,0 +1,33 @@
# Splunk Visualization App Template
This is the basic template for a splunk visualization app. This teamplate is meant to be edited to build custom visualizations. It contains:
- The relevant directory structure for a visuzliation app
- A standin visualization pacakge directory with a standin visualiztion and a basic webpack configuration
- Relevant .conf files for the visualization
## Building the visualization
NOTE: You must have npm installed in oder to build. If you do not have npm installed, install it and come back.
The visualization contained in this app must be built using web pack in order to run it on Splunk. There is a basic webpack configuration built in to the app. To build from the command line, first, cd to the *visualization/standin* directory. On the first run you will have to install the dependeincies with npm:
```
$ npm install
```
Once you done that, you can build the viz with the provided build task:
```
$ npm run build
```
This will create a *visualization.js* file in the visualization directory.
## Adding Your Own Code
The standin viz isn't very interesting, so you will want to add your own code. You should rename the *visualization/src/standin.js* file to something appropriate, then you can edit it as you see fit. To build, you will have to change the `entry` variable in *visualization/webpack.config* to corespond to your new file name. Then you can run the build task again.
## More Information
For more information on building custom visualizations including a tutorial, API overview, and more see:
http://docs.splunk.com/Documentation/Splunk/6.4.0/AdvancedDev/CustomVizDevOverview

@ -0,0 +1,59 @@
<form class="splunk-formatter-section" section-label="General">
<splunk-control-group label="Show Animation Controls" help=" ">
<splunk-radio-input name="{{VIZ_NAMESPACE}}.showAnimationBar" value="0">
<option value="1">Yes</option>
<option value="0">No</option>
</splunk-radio-input>
</splunk-control-group>
<splunk-control-group label="Background Color" help=" ">
<splunk-color-picker name="{{VIZ_NAMESPACE}}.bgColor" value="#000011">
</splunk-color-picker>
</splunk-control-group>
<splunk-control-group label="Nodes Color" help=" ">
<splunk-color-picker name="{{VIZ_NAMESPACE}}.ndColor" value="#EDCBB1">
</splunk-color-picker>
</splunk-control-group>
<splunk-control-group label="Links Color" help=" ">
<splunk-color-picker name="{{VIZ_NAMESPACE}}.lkColor" value="#ffffff">
</splunk-color-picker>
</splunk-control-group>
</form>
<form class="splunk-formatter-section" section-label="Canvas Format">
<splunk-control-group label="Use 3D" help=" ">
<splunk-radio-input name="{{VIZ_NAMESPACE}}.enable3D" value="1">
<option value="1">Yes</option>
<option value="0">No</option>
</splunk-radio-input>
</splunk-control-group>
<splunk-control-group label="Show Directional Arrows" help=" ">
<splunk-radio-input name="{{VIZ_NAMESPACE}}.showLinkArrows" value="0">
<option value="1">Yes</option>
<option value="0">No</option>
</splunk-radio-input>
</splunk-control-group>
<splunk-control-group label="DAG Orientation" help=" ">
<splunk-select name="{{VIZ_NAMESPACE}}.dagMode" value="null">
<option value="null">disabled</option>
<option value="td">top-down</option>
<option value="bu">bottom-up</option>
<option value="lr">left-to-right</option>
<option value="rl">right-to-left</option>
<option value="zout">near-to-far (3D only)</option>
<option value="zin">far-to-near (3D only)</option>
<option value="radialout">outwards-radially</option>
<option value="radialin">inwards-radially</option>
</splunk-select>
</splunk-control-group>
<div>
<span style="display:block; margin: 15px 0px 15px 20px; font-size: 85%; color: #999;">
3D Settings
</span>
</div>
<splunk-control-group label="Camera Controller" help=" ">
<splunk-select name="{{VIZ_NAMESPACE}}.cameraController" value="trackball">
<option value="trackball">trackball</option>
<option value="orbit">orbit</option>
<option value="fly">fly</option>
</splunk-select>
</splunk-control-group>
</form>

@ -0,0 +1,25 @@
{
"name": "3d_graph_network_topology_viz",
"version": "1.3.2",
"description": "Plot relationships between objects with force directed graph based on ThreeJS/WebGL.",
"main": "visualization.js",
"type": "module",
"scripts": {
"build": "$SPLUNK_HOME/bin/splunk cmd node ./node_modules/webpack/bin/webpack.js",
"devbuild": "$SPLUNK_HOME/bin/splunk cmd node ./node_modules/webpack/bin/webpack.js --progress",
"watch": "$SPLUNK_HOME/bin/splunk cmd node ./node_modules/webpack/bin/webpack.js -d --watch --progress"
},
"author": "Splunk",
"license": "Apache-2.0",
"devDependencies": {
"webpack": "^4.0.0",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"d3": "^5.7.0",
"jquery": ">=3.5.0",
"underscore": "^1.12.1",
"3d-force-graph": "^1.68.0",
"force-graph": "^1.36.2"
}
}

@ -0,0 +1,479 @@
/*
* Visualization source
*/
define([
'jquery',
'underscore',
'api/SplunkVisualizationBase',
'api/SplunkVisualizationUtils',
'd3',
'3d-force-graph',
'force-graph'
// Add required assets to this list
],
function(
$,
_,
SplunkVisualizationBase,
SplunkVisualizationUtils,
d3,
ForceGraph3D,
ForceGraph
) {
var MAX_EDGE_SZ = 18; // 18px
var MIN_LARGE_GRAPH = 500;
var COLOR_SRC_NODE_FIELDNAME = "color_src";
var COLOR_DEST_NODE_FIELDNAME = "color_dest";
var SZ_SRC_NODE_FIELDNAME = "weight_src";
var SZ_DEST_NODE_FIELDNAME = "weight_dest";
var COLOR_EDGE_FIELDNAME = "edge_color";
var SZ_EDGE_FIELDNAME = "edge_weight";
// Extend from SplunkVisualizationBase
return SplunkVisualizationBase.extend({
initialize: function() {
this.logging = false;
if(this.logging) console.log('initialize() - Entered');
SplunkVisualizationBase.prototype.initialize.apply(this, arguments);
this.graph = null;
this.hasToggledGraph = false;
this.disableDagMode = false;
this.$el = $(this.el);
this.uuid = this._getUUID();
// this.$el.css('id','viz_base')
this.$el.append('<div class="graphviz-container" name="' + this.uuid + '"></div>');
var controllerbar = '<div class="graphviz-controllers" name="cntl' + this.uuid + '">' +
'<a id="btnPlayAnimation" style="margin: 8px;" href="#" class="btn btn-primary">' +
'<i class="icon-play"></i></a>' +
'<a id="btnPauseAnimation" style="margin: 8px;" href="#" class="btn btn-primary">' +
'<i class="icon-pause"></i></a>' +
'</div>';
this.$el.append(controllerbar);
var that = this;
setTimeout(() => {
$('div[name=cntl'+that.uuid+'] > a#btnPlayAnimation').on('click', event => {
event.preventDefault(); // to avoid re-direction
that._toggleAnimation(1);
});
$('div[name=cntl'+that.uuid+'] > a#btnPauseAnimation').on('click', event => {
event.preventDefault(); // to avoid re-direction
that._toggleAnimation(0);
});
}, 100);
},
// Called at every change to visualization format
// config contains only the change to the viz configuration
onConfigChange: function(config) {
if(this.logging) console.log('onConfigChange() - Entered');
var key_tokens = Object.keys(config)[0].split(/[\s.]+/);
if (this.disableDagMode && ('dagMode') === key_tokens[key_tokens.length-1]) {
var dagMode = this._normalizeNull(this._getEscapedProperty('dagMode', config) || 'null');
if (dagMode !== null) {
// Show error
$('splunk-select[name$=dagMode] > a').css("border", "2px solid red");
var errMsg = "DAG mode must be disabled as current data contains cycle nodes",
errMsgHtml = '<div class="error-msg">' +
'<span>' + errMsg + '</span>' +
'</div>';
if ($('div.error-msg').length < 1)
$('splunk-select[name$=dagMode]').parents('splunk-control-group').append(errMsgHtml);
return;
}
// Remove error message and restore style
$('splunk-select[name$=dagMode] > a').css("border", "1px solid rgb(195, 203, 212)");
$('div.error-msg').remove();
}
if ('showAnimationBar' === key_tokens[key_tokens.length-1]){
// Show / Hide Animation bar
var showAnimationBar = SplunkVisualizationUtils.normalizeBoolean(this._getEscapedProperty('showAnimationBar', config));
this._toggleAnimationBar(showAnimationBar);
return;
}
// Keep track of 2D-3D graph toggle
this.hasToggledGraph = ('enable3D' === key_tokens[key_tokens.length - 1]);
if (this.hasToggledGraph || key_tokens[key_tokens.length - 1].endsWith("Color")
|| key_tokens[key_tokens.length - 1].endsWith('LinkArrows')) {
// 3D / 2D Graph toggled | Color changed | Arrows state changed --> Force viz re-render.
this.invalidateUpdateView();
return;
}
this.invalidateFormatData();
},
// Optionally implement to format data returned from search.
// The returned object will be passed to updateView as 'data'
formatData: function(data) {
if(this.logging) console.log('formatData() - Entered');
// Expects:
// <search> | stats count by src dst
var config = this.getCurrentConfig();
var fields = data.fields;
var rows = data.rows;
var that = this;
var nodes = [],
links = [],
idxLkColor = -1,
idxLkWidth = fields.findIndex(obj => obj.name === SZ_EDGE_FIELDNAME),
idxNdColor = -1,
idxNdSize = -1,
idxNdColorDst = -1,
idxNdSizeDst = -1;
if (rows.length < 1 && fields.length < 1) {
return false;
}
// Extra customisation fields given
if (fields.length > 3) {
if(this.logging) console.log('formatData() - Got extra customisation fields');
idxNdColor = fields.findIndex(obj => obj.name === COLOR_SRC_NODE_FIELDNAME);
idxNdSize = fields.findIndex(obj => obj.name === SZ_SRC_NODE_FIELDNAME);
idxNdColorDst = fields.findIndex(obj => obj.name === COLOR_DEST_NODE_FIELDNAME);
idxNdSizeDst = fields.findIndex(obj => obj.name === SZ_DEST_NODE_FIELDNAME);
idxLkColor = fields.findIndex(obj => obj.name === COLOR_EDGE_FIELDNAME);
}
// Avoid duplicates!
let nodeIds = new Set();
var defaultColors = {
"node": this._getEscapedProperty('ndColor', config) || '#EDCBB1',
"link": this._getEscapedProperty('lkColor', config) || '#ffffff'
};
_.each(rows, function(row) {
// Iterating over 0-1 to get row columns
_.each([...Array(2).keys()], function(ix) {
var id = row[ix],
name = id;
// name = fields[ix].name + ": " + id;
if (!nodeIds.has(id)){
var newNode = {
"id": id,
"name": name,
"val": 1,
"has_custom_color": 0,
"color": defaultColors['node']
};
// Setting custom weigth and colors
if (ix < 1) {
if (idxNdColor > 0) {
newNode['color'] = row[idxNdColor];
newNode['has_custom_color'] = 1;
}
if (idxNdSize > 0) newNode['val'] = row[idxNdSize];
} else {
if (idxNdColorDst > 0) {
newNode['color'] = row[idxNdColorDst];
newNode['has_custom_color'] = 1;
}
if (idxNdSizeDst > 0) newNode['val'] = row[idxNdSizeDst];
}
// Sanity checks
if (newNode.hasOwnProperty('color')) {
if (newNode['color'] && !newNode['color'].match("^#")) {
throw new SplunkVisualizationBase.VisualizationError(
'Check the Statistics tab. To assign custom colors to nodes, valid hex codes shall be returned.'
);
}
}
if (newNode['val'] && newNode['val'] != parseFloat(newNode['val'])) {
throw new SplunkVisualizationBase.VisualizationError(
'Check the Statistics tab. To assign custom weights to nodes, valid numbers shall be returned.'
);
}
nodes.push(newNode);
nodeIds.add(id);
}
});
// Check for loops in data > DAG mode limited
if (row[0] === row[1]) that.disableDagMode = true;
var newLink = {
"source": row[0],
"target": row[1],
"width": idxLkWidth > 0 ? row[idxLkWidth] : 0,
"has_custom_color": 0,
"color": defaultColors['link']
};
// Setting custom color to link
if (idxLkColor > 0 && row[idxLkColor].length > 0) {
// Sanity checks
if (!row[idxLkColor].match("^#")) {
throw new SplunkVisualizationBase.VisualizationError(
'Check the Statistics tab. To assign custom colors to edges, valid hex codes shall be returned.'
);
}
newLink["color"] = row[idxLkColor];
newLink["has_custom_color"] = 1;
}
links.push(newLink);
});
return {
"fields": fields,
"content": {
"nodes": nodes,
"links": links
},
"status": data.meta.done
};
},
// Implement updateView to render a visualization.
// 'data' will be the data object returned from formatData or from the search
// 'config' will be the configuration property object
updateView: function(data, config) {
if (this.logging) console.log("updateView() - Entering");
var $elem = $('div.graphviz-container[name=' + this.uuid + ']');
// check for data
if (!data || data.content.nodes.length < 1) {
if (this.logging) console.log('updateView() - Error: no data');
return;
}
// check for data readiness
if (!data.status) {
if (this.logging) console.log("Search job is still running. Please wait.");
// Trying to dispose here
this._disposeGraph($elem);
return;
}
const isLarge = data.content.nodes.length > MIN_LARGE_GRAPH;
var enable3D = SplunkVisualizationUtils.normalizeBoolean(this._getEscapedProperty('enable3D', config));
var showAnimationBar = SplunkVisualizationUtils.normalizeBoolean(this._getEscapedProperty('showAnimationBar', config));
var showLinkArrows = SplunkVisualizationUtils.normalizeBoolean(this._getEscapedProperty('showLinkArrows', config));
var params = {
"bgColor": this._getEscapedProperty('bgColor', config) || '#000011',
"dagMode": this._normalizeNull(this._getEscapedProperty('dagMode', config) || 'null'),
"lkColor": this._getEscapedProperty('lkColor', config) || '#ffffff',
"ndColor": this._getEscapedProperty('ndColor', config) || '#EDCBB1',
"cameraController": this._getEscapedProperty('cameraController', config) || 'trackball',
"isLarge": isLarge,
"warmupTicks": isLarge ? Math.pow(data.content.nodes.length, 0.7) * 4 : 0
};
this.useDrilldown = this._isEnabledDrilldown(config);
// Show/Hide Animation Bar
this._toggleAnimationBar(showAnimationBar);
// Dispose current graph
if (this.hasToggledGraph) {
this._disposeGraph($elem);
}
// Create the required graph
if (enable3D) {
if (this.graph == null){
if (this.logging) console.log("updateView() - Loading [3D] graph");
this._load3DGraph($elem.get(0), params);
}
if (this.logging) console.log("updateView() - Rendering [3D] graph");
} else {
if (this.graph == null){
if (this.logging) console.log("updateView() - Loading [2D] graph");
this._load2DGraph($elem.get(0), params);
}
if (this.logging) console.log("updateView() - Rendering [2D] graph");
}
this.graph.linkColor(link => link.color =
link.has_custom_color < 1 ? params['lkColor'] : link.color)
.nodeColor(node => node.color =
node.has_custom_color < 1 ? params['ndColor'] : node.color)
.backgroundColor(params["bgColor"])
.dagMode(params["dagMode"])
.linkDirectionalArrowLength(showLinkArrows ? 3.5 : 0)
.linkDirectionalArrowRelPos(1)
.graphData(data.content);
},
// Search data params
getInitialDataParams: function() {
return ({
outputMode: SplunkVisualizationBase.ROW_MAJOR_OUTPUT_MODE,
count: 0
});
},
_disposeGraph: function($elem) {
if (this.graph != null) {
if (this.logging) console.log("_disposeGraph() - Disposing currently rendered graph");
// Stop frame animation engine + Clean data structure
this.graph._destructor();
// Dispose the WebGL renderer (3D graph only)
if (typeof this.graph.renderer == 'function') {
this.graph.renderer().dispose();
}
// Remove all child nodes from DOM
$elem.empty();
this.graph = null;
}
},
_load2DGraph: function(elem, params){
var that = this;
this.graph = ForceGraph.default()(elem)
.backgroundColor(params['bgColor'])
.warmupTicks(params["warmupTicks"])
.cooldownTime(5000)
.linkWidth(link => link.width > MAX_EDGE_SZ ? MAX_EDGE_SZ : link.width)
.dagMode(params['dagMode'])
.onNodeHover(node => {
// Change cursor when hovering on nodes (if drilldown enabled)
elem.style.cursor = node && that.useDrilldown ? 'pointer' : null;
})
.onNodeClick(that._drilldown.bind(that));
},
_load3DGraph: function(elem, params){
const distance = 1000;
var that = this;
this.graph = ForceGraph3D.default({ controlType: params['cameraController'] })(elem)
.nodeResolution(params["isLarge"] ? 4 : 8)
.linkDirectionalArrowResolution(params["isLarge"] ? 4 : 8)
.linkResolution(params["isLarge"] ? 3 : 6)
.cooldownTime(5000) // freeze layout engine after 5s
.warmupTicks(params["warmupTicks"]) // set no of layout engine cycles to dry-run before start rendering
.cameraPosition({ z: distance })
.onNodeHover(node => {
// Change cursor when hovering on nodes (if drilldown enabled)
elem.style.cursor = node && that.useDrilldown ? 'pointer' : null;
})
.onNodeClick(that._drilldown.bind(that))
.backgroundColor(params['bgColor'])
.linkWidth(link => link.width > MAX_EDGE_SZ ? MAX_EDGE_SZ : link.width)
.dagMode(params['dagMode']);
},
_getUUID: function () {
return '_' + Math.random().toString(36).substr(2, 9);
},
_isEnabledDrilldown: function(config) {
return (config['display.visualizations.custom.drilldown']
&& config['display.visualizations.custom.drilldown'] === 'all');
},
_drilldown: function(d, i) {
if(this.logging) console.log("drilldown() - Entered");
var fields = this.getCurrentData().fields;
var drilldownDescription = {
action: SplunkVisualizationBase.FIELD_VALUE_DRILLDOWN,
data: {}
};
drilldownDescription.data[fields[0].name] = d.id;
this.drilldown(drilldownDescription, d3.event);
},
_getEscapedProperty: function(name, config) {
var propertyValue = config[this.getPropertyNamespaceInfo().propertyNamespace + name];
if (propertyValue !== undefined ) propertyValue = propertyValue.replace(/"/g, '');
return SplunkVisualizationUtils.escapeHtml(propertyValue);
},
_toggleAnimation: function(value) {
if(this.logging) console.log('_toggleAnimation() - Resuming Animation ? ' + value);
var resumeAnimation = SplunkVisualizationUtils.normalizeBoolean(value);
var config = this.getCurrentConfig();
var enable3D = SplunkVisualizationUtils.normalizeBoolean(this._getEscapedProperty('enable3D', config));
if (enable3D) {
resumeAnimation ? this.graph.resumeAnimation() : this.graph.pauseAnimation();
return;
}
// Handle Animation for 2D Graph
if (!resumeAnimation) {
this.graph.pauseAnimation();
this.graph.enableZoomPanInteraction(false);
// Work-around a library misbehaviour
var max = 2,
cnt = 0,
id = setInterval(() => {
while(cnt < max) {
this.graph.resumeAnimation();
this.graph.pauseAnimation();
cnt = cnt + 1;
}
clearInterval(id);
}, 50);
return;
}
// Work-around a library misbehaviour
this.graph.pauseAnimation();
this.graph.resumeAnimation();
this.graph.enableZoomPanInteraction(true);
},
_toggleAnimationBar: function(value) {
if (this.logging) console.log("_toggleAnimationBar() - Entered {"+value+"}");
var $elem = $('div.graphviz-controllers[name=cntl'+this.uuid+']');
if (value && !$elem.hasClass("show")) {
$elem.toggleClass("show");
} else if (!value && $elem.hasClass("show")) {
$elem.toggleClass("show");
}
},
_hexToRgb: function(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return "rgb(" + parseInt(result[1], 16)
+ "," + parseInt(result[2], 16)
+ "," + parseInt(result[3], 16) + ")";
},
_normalizeNull: function(value) {
return value === "null" ? null : value;
}
});
});

@ -0,0 +1,38 @@
/*
* CSS rules for visualization.
* Class namespacing is good practice.
*/
div.graphviz-container[name^='3d_'] {
display: block;
}
div.graphviz-container[name^='3d_'].hide {
display: none;
}
div.graphviz-container[name^='_'] {
display: block;
}
div.graphviz-container[name^='_'].hide {
display: none;
}
div.graphviz-controllers {
position: absolute;
top: 5px;
right: 5px;
display: none;
}
div.graphviz-controllers.show {
display: block;
}
div.error-msg > span {
display:block;
margin: 2px 0 0 120px;
font-size: 85%;
color: red;
}

@ -0,0 +1,22 @@
import webpack from 'webpack';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
mode: "development",
entry: {
filename: path.join(__dirname, 'src') + '/visualization_source.js'
},
output: {
path: __dirname,
filename: 'visualization.js',
libraryTarget: 'amd'
},
externals: [
'api/SplunkVisualizationBase',
'api/SplunkVisualizationUtils'
]
};

@ -0,0 +1,72 @@
#!/usr/bin/env python
from base import BaseAlgo, TransformerMixin
from codec import codecs_manager
from util.param_util import convert_params
import pandas as pd
import networkx as nx
from cexc import get_messages_logger, get_logger
debug = get_messages_logger()
class GraphCentrality(TransformerMixin, BaseAlgo):
def __init__(self, options):
debug.info('NetworkX Version {}'.format( nx.__version__))
self.handle_options(options)
out_params = convert_params(
options.get('params', {}),
strs=['compute'],
ints=['max_iter']
)
if 'max_iter' not in out_params:
options['max_iter']=1000
else:
options['max_iter'] = out_params['max_iter']
if 'compute' not in out_params:
options['compute']='degree_centrality'
else:
options['compute'] = out_params['compute']
# call same logic as in fit
def apply(self, df, options):
return self.fit(df, options)
# compute centrality scores
def fit(self, df, options):
# Make a copy of data, to not alter original dataframe
X = df.copy()
# create the graph
graph = nx.Graph()
src_dest_name = self.feature_variables
dfg = X[src_dest_name]
for index, row in dfg.iterrows():
graph.add_edge(row[src_dest_name[0]], row[src_dest_name[1]]) #, value=row['value'])
# compute centrality
algos = options["compute"].lstrip("\"").rstrip("\"").lower().split(',')
outputcolumns = []
for algo in algos:
if algo=='degree_centrality':
cents = nx.algorithms.centrality.degree_centrality(graph)
outputcolumns.append(algo)
elif algo=='betweenness_centrality':
cents = nx.algorithms.centrality.betweenness_centrality(graph)
outputcolumns.append(algo)
elif algo=='eigenvector_centrality':
cents = nx.algorithms.centrality.eigenvector_centrality(graph, max_iter=options["max_iter"])
outputcolumns.append(algo)
elif algo=='cluster_coefficient':
cents = nx.algorithms.cluster.clustering(graph)
outputcolumns.append(algo)
else:
continue
degs = pd.DataFrame(list(cents.items()), columns=[src_dest_name[0], algo])
X = X.join(degs.set_index(src_dest_name[0]), on=src_dest_name[0])
# return results
return X
@staticmethod
def register_codecs():
from codec.codecs import SimpleObjectCodec
codecs_manager.add_codec('mltk_graph.GraphCentrality', 'GraphCentrality', SimpleObjectCodec)

@ -0,0 +1,49 @@
#!/usr/bin/env python
from base import BaseAlgo, TransformerMixin
from codec import codecs_manager
from util.param_util import convert_params
import pandas as pd
import networkx as nx
from cexc import get_messages_logger, get_logger
debug = get_messages_logger()
class GraphConnectedComponents(TransformerMixin, BaseAlgo):
def __init__(self, options):
debug.info('NetworkX Version {}'.format( nx.__version__))
self.handle_options(options)
# call same logic as in fit
def apply(self, df, options):
return self.fit(df, options)
# compute connected components
def fit(self, df, options):
# Make a copy of data, to not alter original dataframe
X = df.copy()
# create a directed graph
graph = nx.DiGraph()
src_dest_name = self.feature_variables
dfg = X[src_dest_name]
for index, row in dfg.iterrows():
graph.add_edge(row[src_dest_name[0]], row[src_dest_name[1]]) #, value=row['value'])
# compute connected components
comps = nx.algorithms.components.weakly_connected_components(graph)
d = dict()
i = 0
for x in comps:
i=i+1
for n in x:
d[n]=i
# join connected components on first key
X = df.join(pd.DataFrame.from_dict(d, orient='index', columns=['connected_component']), on=src_dest_name[0])
# return results
return X
@staticmethod
def register_codecs():
from codec.codecs import SimpleObjectCodec
codecs_manager.add_codec('mltk_graph.GraphConnectedComponents', 'GraphConnectedComponents', SimpleObjectCodec)

@ -0,0 +1,49 @@
#!/usr/bin/env python
from base import BaseAlgo, TransformerMixin
from codec import codecs_manager
from util.param_util import convert_params
import pandas as pd
import networkx as nx
from cexc import get_messages_logger, get_logger
debug = get_messages_logger()
class GraphLabelPropagation(TransformerMixin, BaseAlgo):
def __init__(self, options):
debug.info('NetworkX Version {}'.format( nx.__version__))
self.handle_options(options)
# call same logic as in fit
def apply(self, df, options):
return self.fit(df, options)
# compute connected components
def fit(self, df, options):
# Make a copy of data, to not alter original dataframe
X = df.copy()
# create a directed graph
graph = nx.Graph()
src_dest_name = self.feature_variables
dfg = X[src_dest_name]
for index, row in dfg.iterrows():
graph.add_edge(row[src_dest_name[0]], row[src_dest_name[1]]) #, value=row['value'])
# compute label propagation
comps = nx.algorithms.community.label_propagation.label_propagation_communities(graph)
d = dict()
i = 0
for x in comps:
i=i+1
for n in x:
d[n]=i
# join connected components on first key
X = df.join(pd.DataFrame.from_dict(d, orient='index', columns=['labeled_community']), on=src_dest_name[0])
# return results
return X
@staticmethod
def register_codecs():
from codec.codecs import SimpleObjectCodec
codecs_manager.add_codec('mltk_graph.GraphLabelPropagation', 'GraphLabelPropagation', SimpleObjectCodec)

@ -0,0 +1,62 @@
#!/usr/bin/env python
from base import BaseAlgo, TransformerMixin
from codec import codecs_manager
from util.param_util import convert_params
import pandas as pd
import numpy as np
import networkx as nx
from cexc import get_messages_logger, get_logger
debug = get_messages_logger()
class MinimumSpanningTree(TransformerMixin, BaseAlgo):
def __init__(self, options):
debug.info('NetworkX Version {}'.format( nx.__version__))
self.handle_options(options)
out_params = convert_params(
options.get('params', {}),
strs=['weight']
)
if 'weight' not in out_params:
options['weight']='one'
else:
options['weight'] = out_params['weight']
# call same logic as in fit
def apply(self, df, options):
return self.fit(df, options)
# compute centrality scores
def fit(self, df, options):
# Make a copy of data, to not alter original dataframe
X = df.copy()
# create the graph
G = nx.Graph()
src_dest_name = self.feature_variables
X['join_key'] = X[src_dest_name[0]].apply(str)+'_'+X[src_dest_name[1]].apply(str)
if options['weight']=='one':
for index, row in X.iterrows():
G.add_edge(row[src_dest_name[0]],row[src_dest_name[1]], weight=1)
else:
for index, row in X.iterrows():
G.add_edge(row[src_dest_name[0]],row[src_dest_name[1]], weight=row[options['weight']])
T = nx.minimum_spanning_tree(G)
Y = pd.DataFrame(columns=['source','destination'])
for e in T.edges():
Y = Y.append({'source': e[0], 'destination': e[1]}, ignore_index=True)
Y['join_key'] = Y['source'].apply(str)+'_'+Y['destination'].apply(str)
X = pd.merge(X,Y['join_key'],on='join_key',how='inner')
X.drop('join_key', axis=1, inplace=True)
return X
@staticmethod
def register_codecs():
from codec.codecs import SimpleObjectCodec
codecs_manager.add_codec('mltk_graph.MinimumSpanningTree', 'MinimumSpanningTree', SimpleObjectCodec)

@ -0,0 +1,11 @@
[GraphCentrality]
package=mltk_graph
[GraphConnectedComponents]
package=mltk_graph
[GraphLabelPropagation]
package=mltk_graph
[MinimumSpanningTree]
package=mltk_graph

@ -0,0 +1,19 @@
[install]
is_configured = false
build = 3
[package]
id = splunk-3D-graph-network-topology-viz
[ui]
is_visible = true
label = 3D Graph Network Topology Viz
[launcher]
author = Erica Pescio, Philipp Drieger, Greg Ainslie-Malik
description = Graph Algorithms examples and Custom Visualization to plot relationships between objects with force directed graph based on ThreeJS/WebGL.
version = 1.3.2
[triggers]
reload.algos = simple

@ -0,0 +1,10 @@
<nav search_view="search">
<view name="search" default='true' />
<view name="graph_analysis" />
<collection label="Graph Examples">
<view name="graph_analysis_example_for_bitcoin_transactions"/>
<view name="graph_analysis_example_for_network_traffic"/>
<view name="graph_analysis_example_connected_components"/>
<view name="graph_analysis_example_label_propagation"/>
</collection>
</nav>

@ -0,0 +1,245 @@
<form script="searchcontrolsevents.js" stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<init>
<set token="show_results">true</set>
<set token="beforeSearch">true</set>
</init>
<label>Graph Analysis Framework</label>
<fieldset submitButton="false"></fieldset>
<row>
<panel>
<html>
<div class="ga_framework_intro">
<p>This dashboard is designed to help you generate some graph analytics on your own data. The search bar can be used to input some base data and graph visuals can then be generated by selecting a source field (such as src_ip) as destination field (such as dest_ip) and a weight field (such as the count of connections between src_ip and dest_ip pairs).</p>
</div>
</html>
</panel>
<panel>
<html>
<div class="ga_framework_info">
<h3>Eager to discover more?</h3>
<p>Four dashboards are embedded to show graph algorithms in action using NetworkX. Select them by clicking on <code>Graph Examples</code> dropdown in the app navigation bar.</p>
<p>More uses cases are described in Splunk Blogs posts:</p>
<ul>
<li>
<a class="external" href="https://www.splunk.com/en_us/blog/machine-learning/chasing-a-hidden-gem-graph-analytics-with-splunk-s-machine-learning-toolkit.html">Chasing a Hidden Gem: Graph Analytics with Splunks Machine Learning Toolkit</a>
</li>
<li>Understanding and baselining network behaviour [ <a class="external" href="https://www.splunk.com/en_us/blog/machine-learning/understanding-and-baselining-network-behaviour-using-machine-learning-part-i.html">part 1</a> | <a class="external" href="https://www.splunk.com/en_us/blog/machine-learning/understanding-and-baselining-network-behaviour-using-machine-learning-part-ii.html">part 2</a> ]</li>
</ul>
</div>
</html>
</panel>
<panel depends="$alwaysHideThisPanel$">
<input type="text" token="searchString">
<label>$searchString$</label>
</input>
</panel>
</row>
<row>
<panel depends="$beforeSearch$">
<html>
<div class="ga_framework_inputdata">
<h1>1. Input Data</h1>
<div>
<p style="margin-bottom:0px;">Either run your own search or select one of the example options below, with the first option returning a selection of records from the <a class="external" href="https://www.hs-coburg.de/forschung/forschungsprojekte-oeffentlich/informationstechnologie/cidds-coburg-intrusion-detection-data-sets.html">Coburg Intrusion Detection Data Set (CIDDS)</a></p>
<p> Once the search has run, select a source, destination and weight field to visualise the results.</p>
</div>
<button type="button" id="cidds" class="btn btn-primary">Populate Search with CIDDS Data</button>
<button type="button" id="bitcoin" class="btn btn-primary">Populate Search with Bitcoin Data</button>
<button type="button" id="internal" class="btn btn-primary">Populate Search with Internal Log Data</button>
</div>
</html>
</panel>
</row>
<row>
<panel>
<html>
<div>
<div class="main-area">
<div id="mysearchbar1"/>
<div id="mysearchcontrols1"/>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel depends="$searchString$">
<table>
<title>Search results</title>
<search base="base">
<query>| table *</query>
</search>
<option name="drilldown">none</option>
</table>
</panel>
</row>
<row>
<panel depends="$searchString$">
<html>
<h1>2. Select Fields</h1>
</html>
</panel>
</row>
<row>
<panel depends="$searchString$">
<input type="dropdown" token="source">
<label>Select Source Field:</label>
<fieldForLabel>field</fieldForLabel>
<fieldForValue>field</fieldForValue>
<search base="base">
<query>| table *
| fieldsummary
| table field
| dedup field</query>
</search>
</input>
<input type="dropdown" token="destination">
<label>Select Destination Field:</label>
<fieldForLabel>field</fieldForLabel>
<fieldForValue>field</fieldForValue>
<search base="base">
<query>| table *
| fieldsummary
| table field
| dedup field</query>
</search>
</input>
<input type="dropdown" token="weight">
<label>Select Weight Field:</label>
<fieldForLabel>field</fieldForLabel>
<fieldForValue>field</fieldForValue>
<search base="base">
<query>| table *
| fieldsummary
| search numeric_count&gt;0
| table field
| dedup field</query>
</search>
</input>
</panel>
</row>
<row>
<panel depends="$searchString$">
<html>
<h1>3. Visualise the Results</h1>
</html>
</panel>
</row>
<row>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<title>Simple graph visualisation based on the search results</title>
<search base="base">
<query>| table "$source$" "$destination$" "$weight$"</query>
</search>
<option name="drilldown">none</option>
<option name="height">372</option>
</viz>
</panel>
</row>
<row>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<html>
<h1>4. Further Analysis</h1>
</html>
</panel>
</row>
<row>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<table id="tb_centralitymeasures">
<search>
<query>| makeresults | fields - _time | eval text="Do you want to identify the most critical nodes in your network?" | rename text as "Centrality Measures"</query>
<earliest>$earliest$</earliest>
<latest>$latest$</latest>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="link.visible">false</option>
<drilldown>
<link target="_self">/app/splunk-3D-graph-network-topology-viz/graph_analysis_centrality?form.search=$searchString$&amp;form.source=$source$&amp;form.destination=$destination$&amp;form.weight=$weight$&amp;form.time.earliest=$earliest$&amp;form.time.latest=$latest$</link>
</drilldown>
</table>
<html>
<div style="text-align:center;">
<div class="icon">
<img src="/static/app/splunk-3D-graph-network-topology-viz/images/weighted.png" width="300" height="300"/>
</div>
</div>
</html>
</panel>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<table id="tb_minspanningtree">
<search>
<query>| makeresults | fields - _time | eval text="Do you want to find the shortest path through your network?" | rename text as "Minimum Spanning Tree"</query>
<earliest>$earliest$</earliest>
<latest>$latest$</latest>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="link.visible">false</option>
<drilldown>
<link target="_self">/app/splunk-3D-graph-network-topology-viz/graph_analysis_minimum_spanning_tree?form.search=$searchString$&amp;form.source=$source$&amp;form.destination=$destination$&amp;form.weight=$weight$&amp;form.time.earliest=$earliest$&amp;form.time.latest=$latest$</link>
</drilldown>
</table>
<html>
<div style="text-align:center;">
<div class="icon">
<img src="/static/app/splunk-3D-graph-network-topology-viz/images/spine.png" width="300" height="300"/>
</div>
</div>
</html>
</panel>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<table id="tb_conncomponents">
<search>
<query>| makeresults | fields - _time | eval text="Do you want to analyse the groups of connected nodes in your network?" | rename text as "Connected Components"</query>
<earliest>$earliest$</earliest>
<latest>$latest$</latest>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="link.visible">false</option>
<drilldown>
<link target="_self">/app/splunk-3D-graph-network-topology-viz/graph_analysis_connected_components?form.search=$searchString$&amp;form.source=$source$&amp;form.destination=$destination$&amp;form.weight=$weight$&amp;form.time.earliest=$earliest$&amp;form.time.latest=$latest$</link>
</drilldown>
</table>
<html>
<div style="text-align:center;">
<div class="icon">
<img src="/static/app/splunk-3D-graph-network-topology-viz/images/connected.png" width="300" height="300"/>
</div>
</div>
</html>
</panel>
<panel depends="$source$,$destination$,$weight$,$searchString$">
<table id="tb_communitydetection">
<search>
<query>| makeresults | fields - _time | eval text="Do you want to analyse the groups of related nodes in your network?" | rename text as "Community Detection"</query>
<earliest>$earliest$</earliest>
<latest>$latest$</latest>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="link.visible">false</option>
<drilldown>
<link target="_self">/app/splunk-3D-graph-network-topology-viz/graph_analysis_label_propagation?form.search=$searchString$&amp;form.source=$source$&amp;form.destination=$destination$&amp;form.weight=$weight$&amp;form.time.earliest=$earliest$&amp;form.time.latest=$latest$</link>
</drilldown>
</table>
<html>
<div style="text-align:center;">
<div class="icon">
<img src="/static/app/splunk-3D-graph-network-topology-viz/images/label.png" width="300" height="300"/>
</div>
</div>
</html>
</panel>
</row>
</form>

@ -0,0 +1,224 @@
<form stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Centrality Measures</label>
<fieldset submitButton="false"></fieldset>
<row>
<panel depends="$alwaysHideThisPanel$">
<input type="text" token="search">
<label>field1</label>
</input>
<input type="text" token="source">
<label>field2</label>
</input>
<input type="text" token="destination">
<label>field3</label>
</input>
<input type="text" token="weight">
<label>field4</label>
</input>
<input type="time" token="time">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</panel>
</row>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p><a class="external" href="https://www.geeksforgeeks.org/network-centrality-measures-in-a-graph-using-networkx-python/">Centrality measures</a> can be used to identify key nodes on a network. That is to say these measures are used to find nodes that have a high degree of influence or connectivity across the overall network.</p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<title>Eigenvector Centrality</title>
<chart>
<title>This is a measure of how connected each node is the network</title>
<search base="base">
<query>| stats max(graph_eigenvector_centrality) as eigenvector_centrality by src | sort - eigenvector_centrality | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="refresh.display">progressbar</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel>
<title>Clustering Coefficient</title>
<chart>
<title>This is a measure of how embedded each node is in the network</title>
<search base="base">
<query>| stats max(graph_cluster_coefficient) as cluster_coefficient by src | sort - cluster_coefficient | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel>
<title>Betweenness Centrality</title>
<chart>
<title>This is a measure of how central each node is with respect to all the connections in the network</title>
<search base="base">
<query>| stats max(graph_betweenness_centrality) as betweenness_centrality by src | sort - betweenness_centrality | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>| eval src_value = ln($weight$+1)
| eventstats mean(graph_*) as mean_* max(graph_*) as max_* max(src_value) as max_src_value
| eval src_weight_eigen=graph_eigenvector_centrality/max_eigenvector_centrality
| eval src_weight_cluster=graph_cluster_coefficient/max_cluster_coefficient
| eval src_weight_betweenness=graph_betweenness_centrality/max_betweenness_centrality
| eval src_value=src_value/max_src_value
| eval cB=replace(toString(floor(55+src_weight_eigen*200),"hex"),"0x","")
| eval cB=substr("00", 0, max(2-len(cB), 0)).cB
| eval cG=replace(toString(floor(55+src_weight_cluster*200),"hex"),"0x","")
| eval cG=substr("00", 0, max(2-len(cG), 0)).cG
| eval cR=replace(toString(floor(55+src_weight_betweenness*200),"hex"),"0x","")
| eval cR=substr("00", 0, max(2-len(cR), 0)).cR
| eval cE=replace(toString(floor(55+src_value*200),"hex"),"0x","")
| eval cE=substr("00", 0, max(2-len(cE), 0)).cE
| eval color_src="#".cR.cG.cB
| eval edge_color="#".cE."4444"
| eval edge_weight=1.0+4.0*src_value
| eval weight_src=7.0*(src_weight_eigen+src_weight_cluster+src_weight_betweenness)+1.0
| table src dest color_src weight_src edge_color edge_weight
| sort - src</query>
</search>
<option name="drilldown">none</option>
<option name="height">675</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<title>Data</title>
<table>
<search id="base">
<query>$search$
| rename $source$ as src $destination$ as dest
| fit GraphCentrality src dest compute="betweenness_centrality,eigenvector_centrality,cluster_coefficient"
| rename eigenvector_centrality as graph_eigenvector_centrality betweenness_centrality as graph_betweenness_centrality cluster_coefficient as graph_cluster_coefficient</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
</table>
</panel>
</row>
</form>

@ -0,0 +1,133 @@
<form stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Connected Components</label>
<fieldset submitButton="false"></fieldset>
<row>
<panel depends="$alwaysHideThisPanel$">
<input type="text" token="search">
<label>field1</label>
</input>
<input type="text" token="source">
<label>field2</label>
</input>
<input type="text" token="destination">
<label>field3</label>
</input>
<input type="text" token="weight">
<label>field4</label>
</input>
<input type="time" token="time">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</panel>
</row>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p>In graph theory, a component, sometimes called a connected component, of an undirected graph is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the supergraph. For example, the graph shown in the illustration has three components. A vertex with no incident edges is itself a component. A graph that is itself connected has exactly one component, consisting of the whole graph.</p>
<p>Source: <a class="external" href="https://en.wikipedia.org/wiki/Component_(graph_theory)">Wikipedia</a></p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<title>Graph Visualization with Nodes coloured by Connected Components</title>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>
| eval color_src="#".upper(substr(md5(connected_component),0,6))
| eval color_dest=color_src
| table src dest color_src color_dest</query>
</search>
<option name="drilldown">none</option>
<option name="height">512</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<title>Connections by Connected Component</title>
<chart>
<search base="base">
<query>
| stats sum(count) as connections by connected_component</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="height">512</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<search id="base">
<query>$search$
| rename $source$ as src $destination$ as dest
| stats count by src dest
| fit GraphConnectedComponents src dest</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
<format type="color" field="connected_component">
<colorPalette type="sharedList"></colorPalette>
<scale type="sharedCategory"></scale>
</format>
</table>
</panel>
</row>
</form>

@ -0,0 +1,109 @@
<dashboard stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Graph Analysis Example: Connected Components</label>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p>In graph theory, a component, sometimes called a connected component, of an undirected graph is a subgraph in which any two vertices are connected to each other by paths, and which is connected to no additional vertices in the supergraph. For example, the graph shown in the illustration has three components. A vertex with no incident edges is itself a component. A graph that is itself connected has exactly one component, consisting of the whole graph.</p>
<p>Source: <a class="external" href="https://en.wikipedia.org/wiki/Component_(graph_theory)">Wikipedia</a></p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<title>Graph Visualization with Nodes coloured by Connected Components</title>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>
| eval color_src="#".upper(substr(md5(connected_component),0,6))
| eval color_dest=color_src
| table src dest color_src color_dest</query>
</search>
<option name="drilldown">none</option>
<option name="height">512</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<title>Connections by Connected Component</title>
<chart>
<search base="base">
<query>
| stats sum(count) as connections by connected_component</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="height">512</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<search id="base">
<query>| inputlookup firewall_traffic.csv
| head 1000
| rename src_ip as src dst_ip as dest
| stats count by src dest
| fit GraphConnectedComponents src dest</query>
<earliest>-24h@h</earliest>
<latest>now</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
<format type="color" field="connected_component">
<colorPalette type="sharedList"></colorPalette>
<scale type="sharedCategory"></scale>
</format>
</table>
</panel>
</row>
</dashboard>

@ -0,0 +1,185 @@
<dashboard theme="dark" version="1.1">
<label>Graph Analysis Example for Bitcoin Transactions</label>
<row>
<panel>
<chart>
<title>Eigenvector Centrality</title>
<search base="base">
<query>| stats max(graph_eigenvector_centrality) as eigenvector_centrality by src | sort - eigenvector_centrality | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="refresh.display">progressbar</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel>
<chart>
<title>Clustering Coefficient</title>
<search base="base">
<query>| stats max(graph_cluster_coefficient) as cluster_coefficient by src | sort - cluster_coefficient | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
<panel>
<chart>
<title>Betweenness Centrality</title>
<search base="base">
<query>| stats max(graph_betweenness_centrality) as betweenness_centrality by src | sort - betweenness_centrality | head 5</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">collapsed</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">bar</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="charting.lineWidth">2</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>
| eval src_value = ln(value+1)
| eventstats mean(graph_*) as mean_* max(graph_*) as max_* max(src_value) as max_src_value
| eval src_weight_eigen=graph_eigenvector_centrality/max_eigenvector_centrality
| eval src_weight_cluster=graph_cluster_coefficient/max_cluster_coefficient
| eval src_weight_betweenness=graph_betweenness_centrality/max_betweenness_centrality
| eval src_value=src_value/max_src_value
| eval cB=replace(toString(floor(55+src_weight_eigen*200),"hex"),"0x","")
| eval cB=substr("00", 0, max(2-len(cB), 0)).cB
| eval cG=replace(toString(floor(55+src_weight_cluster*200),"hex"),"0x","")
| eval cG=substr("00", 0, max(2-len(cG), 0)).cG
| eval cR=replace(toString(floor(55+src_weight_betweenness*200),"hex"),"0x","")
| eval cR=substr("00", 0, max(2-len(cR), 0)).cR
| eval cE=replace(toString(floor(55+src_value*200),"hex"),"0x","")
| eval cE=substr("00", 0, max(2-len(cE), 0)).cE
| eval color_src="#".cR.cG.cB
| eval edge_color="#".cE."4444"
| eval edge_weight=1.0+4.0*src_value
| eval weight_src=7.0*(src_weight_eigen+src_weight_cluster+src_weight_betweenness)+1.0
| table src dest color_src weight_src edge_color edge_weight</query>
</search>
<option name="drilldown">none</option>
<option name="height">517</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
</row>
<row>
<panel>
<title>Data</title>
<table>
<search id="base">
<query>| inputlookup bitcoin_transactions.csv
| head 1000
| rename user_id_from as src user_id_to as dest
| fit GraphCentrality src dest compute="betweenness_centrality,eigenvector_centrality,cluster_coefficient"
| rename eigenvector_centrality as graph_eigenvector_centrality betweenness_centrality as graph_betweenness_centrality cluster_coefficient as graph_cluster_coefficient</query>
<earliest>-24h@h</earliest>
<latest>now</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
</table>
</panel>
</row>
</dashboard>

@ -0,0 +1,51 @@
<dashboard theme="dark" version="1.1">
<label>Graph Analysis Example for Network Traffic</label>
<row>
<panel>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>| eval col0 = "#00AA00"
| eval col1 = "#FF00FF"
`interpolateColor(col0,col1,eigenvector_centrality,"color_src")`
| eval weight_src=1+10*eigenvector_centrality
| eval edge_weight=sqrt(count+1)
| eval color_dest=color_src
| table src dest color_src color_dest weight_src edge_weight
</query>
</search>
<option name="drilldown">none</option>
<option name="height">704</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<table>
<search id="base">
<query>| inputlookup firewall_traffic.csv
| head 1000
| rename src_ip as src dst_ip as dest
| stats count by src dest
| fit GraphCentrality src dest compute="eigenvector_centrality"
</query>
<earliest>-24h@h</earliest>
<latest>now</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
</table>
</panel>
</row>
</dashboard>

@ -0,0 +1,110 @@
<dashboard stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Graph Analysis Example: Label Propagation</label>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p>Label propagation is a semi-supervised machine learning algorithm that assigns labels to previously unlabeled data points. At the start of the algorithm, a (generally small) subset of the data points have labels (or classifications). These labels are propagated to the unlabeled points throughout the course of the algorithm.</p>
<p>Within complex networks, real networks tend to have community structure. Label propagation is an algorithm for finding communities. In comparison with other algorithm label propagation has advantages in its running time and amount of a priori information needed about the network structure (no parameter is required to be known beforehand). The disadvantage is that it produces no unique solution, but an aggregate of many solutions.</p>
<p>Source: <a class="external" href="https://en.wikipedia.org/wiki/Label_propagation_algorithm">Wikipedia</a></p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<title>Graph Visualization with Nodes coloured by Community</title>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>
| eval color_src="#".upper(substr(md5(labeled_community),0,6))
| eval color_dest=color_src
| table src dest color_src color_dest</query>
</search>
<option name="drilldown">none</option>
<option name="height">513</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<title>Connections by Community</title>
<chart>
<search base="base">
<query>
| stats sum(count) as connections by labeled_community</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="height">510</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<search id="base">
<query>| inputlookup firewall_traffic.csv
| head 1000
| rename src_ip as src dst_ip as dest
| stats count by src dest
| fit GraphLabelPropagation src dest</query>
<earliest>-24h@h</earliest>
<latest>now</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
<format type="color" field="labeled_community">
<colorPalette type="sharedList"></colorPalette>
<scale type="sharedCategory"></scale>
</format>
</table>
</panel>
</row>
</dashboard>

@ -0,0 +1,134 @@
<form stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Community Detection</label>
<fieldset submitButton="false"></fieldset>
<row>
<panel depends="$alwaysHideThisPanel$">
<input type="text" token="search">
<label>field1</label>
</input>
<input type="text" token="source">
<label>field2</label>
</input>
<input type="text" token="destination">
<label>field3</label>
</input>
<input type="text" token="weight">
<label>field4</label>
</input>
<input type="time" token="time">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</panel>
</row>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p>An example of community detection is label propagation, a semi-supervised machine learning algorithm that assigns labels to previously unlabeled data points. At the start of the algorithm, a (generally small) subset of the data points have labels (or classifications). These labels are propagated to the unlabeled points throughout the course of the algorithm.</p>
<p>Within complex networks, real networks tend to have community structure. Label propagation is an algorithm for finding communities. In comparison with other algorithm label propagation has advantages in its running time and amount of a priori information needed about the network structure (no parameter is required to be known beforehand). The disadvantage is that it produces no unique solution, but an aggregate of many solutions.</p>
<p>Source: <a class="external" href="https://en.wikipedia.org/wiki/Label_propagation_algorithm">Wikipedia</a></p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<title>Graph Visualization with Nodes coloured by Community</title>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<search base="base">
<query>
| eval color_src="#".upper(substr(md5(labeled_community),0,6))
| eval color_dest=color_src
| table src dest color_src color_dest</query>
</search>
<option name="drilldown">none</option>
<option name="height">513</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
<panel>
<title>Connections by Community</title>
<chart>
<search base="base">
<query>
| stats sum(count) as connections by labeled_community</query>
</search>
<option name="charting.axisLabelsX.majorLabelStyle.overflowMode">ellipsisNone</option>
<option name="charting.axisLabelsX.majorLabelStyle.rotation">0</option>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisTitleY2.visibility">visible</option>
<option name="charting.axisX.abbreviation">none</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.abbreviation">none</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.axisY2.abbreviation">none</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.axisY2.scale">inherit</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.bubbleMaximumSize">50</option>
<option name="charting.chart.bubbleMinimumSize">10</option>
<option name="charting.chart.bubbleSizeBy">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.showDataLabels">none</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.layout.splitSeries.allowIndependentYRanges">0</option>
<option name="charting.legend.labelStyle.overflowMode">ellipsisMiddle</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="charting.lineWidth">2</option>
<option name="height">510</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<search id="base">
<query>$search$
| rename $source$ as src $destination$ as dest
| stats count by src dest
| fit GraphLabelPropagation src dest</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
<format type="color" field="labeled_community">
<colorPalette type="sharedList"></colorPalette>
<scale type="sharedCategory"></scale>
</format>
</table>
</panel>
</row>
</form>

@ -0,0 +1,107 @@
<form stylesheet="searchcontrolsevents.css" theme="dark" version="1.1">
<label>Minimum Spanning Tree</label>
<fieldset submitButton="false"></fieldset>
<row>
<panel depends="$alwaysHidePanel$">
<input type="text" token="search">
<label>search</label>
</input>
<input type="text" token="source">
<label>source</label>
</input>
<input type="text" token="destination">
<label>destination</label>
</input>
<input type="text" token="weight">
<label>weight</label>
</input>
<input type="time" token="time">
<label></label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</panel>
</row>
<row>
<panel>
<html>
<div class="ga_general_info">
<div class="pull-left">
<i class="icon-info large"/>
</div>
<div class="pull-right">
<p>A <a class="external" href="https://en.wikipedia.org/wiki/Minimum_spanning_tree">Minimum Spanning Tree</a> is an algorithm that aims to determine the nodes and connections that form the shortest path across the network - or the 'spine' of the network. It analyses the nodes and connections across a given network and includes each connection in turn starting with the connection with the lowest weighting until all the nodes are connected, ignoring any connections that create a cycle in the network. Combined with some centrality measures it can help identify the most important path across a network.</p>
</div>
</div>
</html>
</panel>
</row>
<row>
<panel>
<viz type="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz">
<title>Network Spine Visualisation</title>
<search base="base">
<query>| table $source$ $destination$ *
| sort - "$source$"</query>
</search>
<option name="drilldown">none</option>
<option name="height">659</option>
<option name="refresh.display">progressbar</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.bgColor">#222527</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.cameraController">trackball</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.dagMode">null</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.enable3D">0</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.lkColor">#777777</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.ndColor">#999999</option>
<option name="splunk-3D-graph-network-topology-viz.3d_graph_network_topology_viz.showAnimationBar">1</option>
</viz>
</panel>
</row>
<row>
<panel>
<table>
<title>Input Data</title>
<search id="base">
<query>$search$
| table $source$ $destination$ $weight$
| fit GraphCentrality $source$ $destination$ compute="betweenness_centrality,eigenvector_centrality,cluster_coefficient"
| rename eigenvector_centrality as graph_eigenvector_centrality betweenness_centrality as graph_betweenness_centrality cluster_coefficient as graph_cluster_coefficient
| eval src_value = ln($weight$+1)
| eventstats mean(graph_*) as mean_* max(graph_*) as max_* max(src_value) as max_src_value
| eval src_weight_eigen=graph_eigenvector_centrality/max_eigenvector_centrality
| eval src_weight_cluster=graph_cluster_coefficient/max_cluster_coefficient
| eval src_weight_betweenness=graph_betweenness_centrality/max_betweenness_centrality
| eval src_value=src_value/max_src_value
| eval cB=replace(toString(floor(55+src_weight_eigen*200),"hex"),"0x","")
| eval cB=substr("00", 0, max(2-len(cB), 0)).cB
| eval cG=replace(toString(floor(55+src_weight_cluster*200),"hex"),"0x","")
| eval cG=substr("00", 0, max(2-len(cG), 0)).cG
| eval cR=replace(toString(floor(55+src_weight_betweenness*200),"hex"),"0x","")
| eval cR=substr("00", 0, max(2-len(cR), 0)).cR
| eval cE=replace(toString(floor(55+src_value*200),"hex"),"0x","")
| eval cE=substr("00", 0, max(2-len(cE), 0)).cE
| eval color_src="#".cR.cG.cB
| eval edge_color="#".cE."4444"
| eval edge_weight=1.0+4.0*src_value
| eval weight_src=7.0*(src_weight_eigen+src_weight_cluster+src_weight_betweenness)+1.0
| table $source$ $destination$ color_src weight_src edge_color edge_weight $weight$
| eventstats max($weight$) as max_count
| eval weight=(1-($weight$/max_count))
| fit MinimumSpanningTree $source$ $destination$ weight='weight'</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
</table>
</panel>
</row>
</form>

@ -0,0 +1,48 @@
[bilinearInterpolateColorGradient(7)]
args = x,y,col00,colX0,col0Y,colXY,outcolorfieldname
definition = | eval _x = $x$\
| eval _y = $y$\
| eval _col00 = $col00$\
| eval _colX0 = $colX0$\
| eval _col0Y = $col0Y$\
| eval _colXY = $colXY$\
`interpolateColor(_col00, _colX0, _x, "_outcolorB")`\
`interpolateColor(_col0Y, _colXY, _x, "_outcolorT")`\
`interpolateColor(_outcolorB, _outcolorT, _y, "_outcolor")`\
| eval $outcolorfieldname$ = _outcolor
iseval = 0
[genColorFromComponents(4)]
args = red,green,blue,outcolorfieldname
definition = | eval _red = $red$\
| eval _green = $green$\
| eval _blue = $blue$\
| eval _outcolor = "#" + upper(printf("%02x", _red)) + upper(printf("%02x", _green)) + upper(printf("%02x", _blue))\
| eval $outcolorfieldname$ = _outcolor
iseval = 0
[interpolateColor(4)]
args = col1,col2,lerpt,outcolorfieldname
definition = | eval _col1 = $col1$\
| eval _col2 = $col2$\
| eval _lerpt = $lerpt$\
| eval _outcolor = "#ZZZZZZ"\
| eval _lerpt = if(_lerpt > 1, 1.0, _lerpt)\
| eval _lerpt = if(_lerpt < 0.0, 0.0, _lerpt)\
`splitColorIntoComponents(_col1, "_col1r", "_col1g", "_col1b")`\
`splitColorIntoComponents(_col2, "_col2r", "_col2g", "_col2b")`\
| eval _deltaRed = _col2r - _col1r, _deltaGreen = _col2g - _col1g, _deltaBlue = _col2b - _col1b\
| eval _outRed = _col1r + _lerpt * _deltaRed, _outGreen = _col1g + _lerpt * _deltaGreen, _outBlue = _col1b + _lerpt * _deltaBlue\
`genColorFromComponents(_outRed, _outGreen, _outBlue, "_outcolor")`\
| eval $outcolorfieldname$ = _outcolor
iseval = 0
[splitColorIntoComponents(4)]
args = color, outfieldname_red,outfieldname_green,outfieldname_blue
definition = | eval _color = $color$\
| rex field=_color "^#(?<_red>[0-9a-zA-Z]{2,2})(?<_green>[0-9a-zA-Z]{2,2})(?<_blue>[0-9a-zA-Z]{2,2})$"\
| eval _red = tonumber(_red, 16), _green = tonumber(_green, 16), _blue = tonumber(_blue, 16)\
| eval $outfieldname_red$ = _red\
| eval $outfieldname_green$ = _green\
| eval $outfieldname_blue$ = _blue
iseval = 0

@ -0,0 +1,6 @@
[default]
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.enable3D = 1
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.showAnimationBar = 0
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.showLinkArrows = 0
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.dagMode = "null"
display.visualizations.custom.3d_graph_network_topology_viz.3d_graph_network_topology_viz.cameraController = "trackball"

@ -0,0 +1,2 @@
[cidds_ip_connections]
filename=cidds_ip_connections.csv

@ -0,0 +1,9 @@
#
# Declare shared visualizations
#
[3d_graph_network_topology_viz]
label = 3D Graph Network Topology Viz
description = Plot relationships between objects with force directed graph based on ThreeJS/WebGL.
search_fragment = | stats count by src dest [color_src] [color_dest] [edge_color] [weight_src] [weight_dest] [edge_weigth]
supports_drilldown = true

@ -0,0 +1,62 @@
# Application-level permissions
[]
access = read : [ * ], write : [ admin, power ]
### EVENT TYPES
[eventtypes]
export = system
### PROPS
[props]
export = system
### TRANSFORMS
[transforms]
export = system
### LOOKUPS
[lookups]
export = system
### VIEWSTATES: even normal users should be able to create shared viewstates
[viewstates]
access = read : [ * ], write : [ * ]
export = system
### Visualizations
[visualizations/3d_graph_network_topology_viz]
export = system
### Algos
[algos]
access = read : [ * ], write : [ admin ]
export = system
[algos/GraphCentrality]
access = read : [*]
export = system
[algos/GraphConnectedComponents]
access = read : [*]
export = system
[algos/GraphLabelPropagation]
access = read : [*]
export = system
[algos/MinimumSpanningTree]
access = read : [*]
export = system

@ -0,0 +1,241 @@
{
"version": "1.0",
"date": "2022-11-12T08:06:41.893569701Z",
"hashAlgorithm": "SHA-256",
"app": {
"id": 4611,
"version": "1.3.2",
"files": [
{
"path": "LICENSE",
"hash": "300a09380aff55e81cdaec9de51c9a48d9234592f8a7722d34ec26eac83d3d27"
},
{
"path": "README.md",
"hash": "424fb5f24ed1204cdb464aa0c68e012c3b9e0b3986ffadb02209048fbeea5e9f"
},
{
"path": "CONTRIBUTING.md",
"hash": "cd8cc1613e4e606928a3a282f1d490cb196e36251ac007c1522af2c8c18f0baa"
},
{
"path": "app.manifest",
"hash": "4fa176f611805c978ef0e2539708e465a5e126a3015e31d253e88c025cb59d67"
},
{
"path": "metadata/default.meta",
"hash": "0afb1863e6e1f123219bd25d10f2be0e495b5073c83b4ba480c216fef72ad64a"
},
{
"path": "appserver/static/searchcontrolsevents.css",
"hash": "3bdc27aaa28ce5e3e98bf9c75a5f45db0c3dcd990295ad730a581b40a53ac7c1"
},
{
"path": "appserver/static/searchcontrolsevents.js",
"hash": "3bdd3d9623d175f903f963ae5294c2c4a2fae8d03b94dd584043145802d0b328"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/preview.png",
"hash": "3b99b2367904a42a1c9f92d7bb2ba07037206dd32fed71d3308f813be785d0b9"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/visualization.js",
"hash": "64359112f0c8b62cf31aa9a1caa98706e72c064232bcedc9f7bc765d93b889bd"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/webpack.config.js",
"hash": "3aa10a91c47ec1fb5ef2beb3b4a11f5178e96792c58f61f07eaf1aabc9870ca4"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/README.md",
"hash": "7deeb11906cdf8e02ab9d94da76c7cb6dee620f9d33ab17cb81f337561774950"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/visualization.css",
"hash": "0365fed050a089a9695a23794eba72ef7254cecb7acfdeb5ef60c3f3dbcb4711"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/package-lock.json",
"hash": "6444b6f981dd11450af44bf4f2103d760574fbbc697c3d4399699eef34f154d6"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/package.json",
"hash": "2e24780fd0900fbbc86e6801720076c056c9258da4cabd1ae27a699f735250d9"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/formatter.html",
"hash": "fc5242dd17efa2efd4987dd667beaad676236febe3c453a000241a384d37b342"
},
{
"path": "appserver/static/visualizations/3d_graph_network_topology_viz/src/visualization_source.js",
"hash": "3fbf79ce04a6690218373b57f43b5aaf34d6180325b193f18b7b841ad66ec53e"
},
{
"path": "appserver/static/images/connected.png",
"hash": "ed783eb8fe71f6d1236165d828ea0a9806ad3ad5c05613dac01156eecc40eab8"
},
{
"path": "appserver/static/images/label.png",
"hash": "06b5e46597a8ebc2304b50d0aa118152ac8a2237a84810e98292f5553df26b5d"
},
{
"path": "appserver/static/images/image",
"hash": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"
},
{
"path": "appserver/static/images/weighted.png",
"hash": "8a45d8f6af24f73efee7310391ddf3771ec373b758cd435c4fe3497a0ec250be"
},
{
"path": "appserver/static/images/spine.png",
"hash": "67b4aa4b8584ad867965dea772c5a1b6c6671ee1a9d0ef3dff6a4421cd9d0e94"
},
{
"path": "static/screenshot.png",
"hash": "e87f86800bc794ea7b6c84955c5a5ceda0ea45f8fb6335ee14c627f4da2cbc17"
},
{
"path": "static/appIcon.png",
"hash": "da9fa1d60e0df91c23c3ccf0dceff01e23ad13ad5c31b41290e8543c634c64bc"
},
{
"path": "static/appIcon_2x.png",
"hash": "08aec034950f994b8aedc7a4d7725f29c52bfd8544e8d1ae708a201495299592"
},
{
"path": "README/savedsearches.conf.spec",
"hash": "b845290a0aa865d3691bea19a304145ef95c83b20fa6abb7735945af6bbe9b3c"
},
{
"path": "default/app.conf",
"hash": "0ce8f034d1d13beb09fa24bb77288a7082f4b18690c8a7586de6e96ed44a8336"
},
{
"path": "default/algos.conf",
"hash": "9b914766cdf03d926837edd0dd10cf50c121fbbb2a48063bec54c1a9cbac0bf8"
},
{
"path": "default/savedsearches.conf",
"hash": "0cf7e738eb5485d405c6b63cab70a679994eade29427c8ef87e38f9ede3212ad"
},
{
"path": "default/macros.conf",
"hash": "94faf28c5315293aa4bcf04d3ce3cc6a8661f63364f09f604597df670617c41e"
},
{
"path": "default/transforms.conf",
"hash": "2c7d038e7d5844a66cc69e45b7805848dea975eb2c6ffce346b746e4c68160b7"
},
{
"path": "default/visualizations.conf",
"hash": "3b4494556d27adeb5268823fb1f4437066674012298db2616a27492651f09813"
},
{
"path": "default/data/ui/views/graph_analysis_minimum_spanning_tree.xml",
"hash": "8bcc55b7a4449f677982acda26573966b3e7b9032a3b70062c0ff92090a0a2ad"
},
{
"path": "default/data/ui/views/graph_analysis_example_connected_components.xml",
"hash": "631346ba265b2ca11974d83f382872fb9146bc7a4c7240a4e177a97111b431b1"
},
{
"path": "default/data/ui/views/graph_analysis_example_for_bitcoin_transactions.xml",
"hash": "928c6e04171211545a6d03c76499f9f1aee6d3ffa1d8d051980108c857c5dcd5"
},
{
"path": "default/data/ui/views/graph_analysis_label_propagation.xml",
"hash": "ecaa382e6384c04f7d2c73b06d1ce6f1f3b619f4374aa65f12bfd39f24d91318"
},
{
"path": "default/data/ui/views/graph_analysis.xml",
"hash": "f8d6473c78bf003299facd86b7f4a8a4ecfdea4c6890e83d762ab50058cf488e"
},
{
"path": "default/data/ui/views/graph_analysis_centrality.xml",
"hash": "63d22bf8ab0c4e30573abb69ad825b13fae6f5798534e8ce53bc984c39cf5a7c"
},
{
"path": "default/data/ui/views/graph_analysis_example_for_network_traffic.xml",
"hash": "41352c68b8f2a4b7bb61a6761d217059d47590b3d059cf85996baec602648978"
},
{
"path": "default/data/ui/views/graph_analysis_connected_components.xml",
"hash": "257ac3a8c7533dbd09e123c928e4f03a3cb06577050d13f865c134fe08c22702"
},
{
"path": "default/data/ui/views/graph_analysis_example_label_propagation.xml",
"hash": "e5cd817b5c70c6cb46effcf2761212b4f698f5a8e6755d6a23bbea3167073e47"
},
{
"path": "default/data/ui/nav/default.xml",
"hash": "da41508bb8a0d2f65ea0e60b6bd72fb0ee5d80f64cecf125095a764237803e80"
},
{
"path": "bin/mltk_graph/MinimumSpanningTree.py",
"hash": "b66b9929854adc902a2efacb805c92be0a204422337d2f76f178504f7b132a9a"
},
{
"path": "bin/mltk_graph/GraphConnectedComponents.py",
"hash": "99f90485ebfed24677b0a03f754f5ace063bb5eb320911909875e982d55dfdb3"
},
{
"path": "bin/mltk_graph/GraphCentrality.py",
"hash": "366eb5a45d48d169f2e8ad8035b8512b0ec22a67f2599c1881c9e021f018443c"
},
{
"path": "bin/mltk_graph/GraphLabelPropagation.py",
"hash": "6886d7dad6624ba5d7b59383cf1d42dbce690196f5bd2339a772cc4cc3b352b2"
},
{
"path": "lookups/cidds_ip_connections.csv",
"hash": "de016278357fe4f5d7c7e0b0ab719c6b27e6be907973505096cc56496fe70314"
}
]
},
"products": [
{
"platform": "splunk",
"product": "enterprise",
"versions": [
"7.3",
"8.0",
"8.1",
"8.2",
"9.0"
],
"architectures": [
"x86_64"
],
"operatingSystems": [
"windows",
"linux",
"macos",
"freebsd",
"solaris",
"aix"
]
},
{
"platform": "splunk",
"product": "cloud",
"versions": [
"7.3",
"8.0",
"8.1",
"8.2",
"9.0"
],
"architectures": [
"x86_64"
],
"operatingSystems": [
"windows",
"linux",
"macos",
"freebsd",
"solaris",
"aix"
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Loading…
Cancel
Save