@ -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,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"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 69 KiB |
@ -0,0 +1 @@
|
||||
|
||||
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
@ -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,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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 82 KiB |