%%INDEX%%-*


%%INDEX%%-Filters

%%INDEX%%-Filters


%%INDEX%%-Total Requests

%%INDEX%%-Total Requests


%%INDEX%%-Request History

%%INDEX%%-Request History

Count


%%INDEX%%-Requests by VPC ID

%%INDEX%%-Requests by VPC ID


%%INDEX%%-Total Requests By Action

%%INDEX%%-Total Requests By Action


%%INDEX%%-Bytes

%%INDEX%%-Bytes

Sum of bytes


%%INDEX%%-Packets

%%INDEX%%-Packets

Sum of bytes


%%INDEX%%-Bytes Metric

%%INDEX%%-Bytes Metric

# **{{ ingress.last.formatted }}**

Ingress Bytes

# **{{ egress.last.formatted }}**

Egress Bytes


%%INDEX%%-Requests by Direction

%%INDEX%%-Requests by Direction


%%INDEX%%-Requests by Direction Metric

%%INDEX%%-Requests by Direction Metric


%%INDEX%%-Requests By Type Bar

%%INDEX%%-Requests By Type Bar

Requests


%%INDEX%%-Top Source Bytes

%%INDEX%%-Top Source Bytes


%%INDEX%%-Top Destination Bytes

%%INDEX%%-Top Destination Bytes


%%INDEX%%-Top Sources

%%INDEX%%-Top Sources


%%INDEX%%-Top Destinations

%%INDEX%%-Top Destinations


%%INDEX%%-Requests by Protocol

%%INDEX%%-Requests by Protocol


%%INDEX%%-Requests by Status

%%INDEX%%-Requests by Status


%%INDEX%%-Top Source AWS Services

%%INDEX%%-Top Source AWS Services


%%INDEX%%-Top Destination AWS Services

%%INDEX%%-Top Destination AWS Services


%%INDEX%%-Flow

%%INDEX%%-Flow

{
 $schema: https://vega.github.io/schema/vega/v5.json
  data: [
	{
  	// query OpenSearch based on the currently selected time range and filter string
  	name: rawData
  	url: {
    	%context%: true
    	%timefield%: start
    	index: %%INDEX%%
    	body: {
      	size: 0
      	aggs: {
        	table: {
          	composite: {
            	size: 10000
            	sources: [
              	{
                	stk1: {
                  	terms: {field: "srcaddr.keyword"}
                	}
              	}
              	{
                	stk2: {
                  	terms: {field: "dstaddr.keyword"}
                	}
              	}
            	]
          	}
        	}
      	}
    	}
  	}
  	// From the result, take just the data we are interested in
  	format: {property: "aggregations.table.buckets"}
  	// Convert key.stk1 -> stk1 for simpler access below
  	transform: [
    	{type: "formula", expr: "datum.key.stk1", as: "stk1"}
    	{type: "formula", expr: "datum.key.stk2", as: "stk2"}
    	{type: "formula", expr: "datum.doc_count", as: "size"}
  	]
	}
	{
  	name: nodes
  	source: rawData
  	transform: [
    	// when a country is selected, filter out unrelated data
    	{
      	type: filter
      	expr: !groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2
    	}
    	// Set new key for later lookups - identifies each node
    	{type: "formula", expr: "datum.stk1+datum.stk2", as: "key"}
    	// instead of each table row, create two new rows,
    	// one for the source (stack=stk1) and one for destination node (stack=stk2).
    	// The country code stored in stk1 and stk2 fields is placed into grpId field.
    	{
      	type: fold
      	fields: ["stk1", "stk2"]
      	as: ["stack", "grpId"]
    	}
    	// Create a sortkey, different for stk1 and stk2 stacks.
    	{
      	type: formula
      	expr: datum.stack == 'stk1' ? datum.stk1+datum.stk2 : datum.stk2+datum.stk1
      	as: sortField
    	}
    	// Calculate y0 and y1 positions for stacking nodes one on top of the other,
    	// independently for each stack, and ensuring they are in the proper order,
    	// alphabetical from the top (reversed on the y axis)
    	{
      	type: stack
      	groupby: ["stack"]
      	sort: {field: "sortField", order: "descending"}
      	field: size
    	}
    	// calculate vertical center point for each node, used to draw edges
    	{type: "formula", expr: "(datum.y0+datum.y1)/2", as: "yc"}
  	]
	}
	{
  	name: groups
  	source: nodes
  	transform: [
    	// combine all nodes into country groups, summing up the doc counts
    	{
      	type: aggregate
      	groupby: ["stack", "grpId"]
      	fields: ["size"]
      	ops: ["sum"]
      	as: ["total"]
    	}
    	// re-calculate the stacking y0,y1 values
    	{
      	type: stack
      	groupby: ["stack"]
      	sort: {field: "grpId", order: "descending"}
      	field: total
    	}
    	// project y0 and y1 values to screen coordinates
    	// doing it once here instead of doing it several times in marks
    	{type: "formula", expr: "scale('y', datum.y0)", as: "scaledY0"}
    	{type: "formula", expr: "scale('y', datum.y1)", as: "scaledY1"}
    	// boolean flag if the label should be on the right of the stack
    	{type: "formula", expr: "datum.stack == 'stk1'", as: "rightLabel"}
    	// Calculate traffic percentage for this country using "y" scale
    	// domain upper bound, which represents the total traffic
    	{
      	type: formula
      	expr: datum.total/domain('y')[1]
      	as: percentage
    	}
  	]
	}
	{
  	// This is a temp lookup table with all the 'stk2' stack nodes
  	name: destinationNodes
  	source: nodes
  	transform: [
    	{type: "filter", expr: "datum.stack == 'stk2'"}
  	]
	}
	{
  	name: edges
  	source: nodes
  	transform: [
    	// we only want nodes from the left stack
    	{type: "filter", expr: "datum.stack == 'stk1'"}
    	// find corresponding node from the right stack, keep it as "target"
    	{
      	type: lookup
      	from: destinationNodes
      	key: key
      	fields: ["key"]
      	as: ["target"]
    	}
    	// calculate SVG link path between stk1 and stk2 stacks for the node pair
    	{
      	type: linkpath
      	orient: horizontal
      	shape: diagonal
      	sourceY: {expr: "scale('y', datum.yc)"}
      	sourceX: {expr: "scale('x', 'stk1') + bandwidth('x')"}
      	targetY: {expr: "scale('y', datum.target.yc)"}
      	targetX: {expr: "scale('x', 'stk2')"}
    	}
    	// A little trick to calculate the thickness of the line.
    	// The value needs to be the same as the hight of the node, but scaling
    	// size to screen's height gives inversed value because screen's Y
    	// coordinate goes from the top to the bottom, whereas the graph's Y=0
    	// is at the bottom. So subtracting scaled doc count from screen height
    	// (which is the "lower" bound of the "y" scale) gives us the right value
    	{
      	type: formula
      	expr: range('y')[0]-scale('y', datum.size)
      	as: strokeWidth
    	}
    	// Tooltip needs individual link's percentage of all traffic
    	{
      	type: formula
      	expr: datum.size/domain('y')[1]
      	as: percentage
    	}
  	]
	}
  ]
  scales: [
	{
  	// calculates horizontal stack positioning
  	name: x
  	type: band
  	range: width
  	domain: ["stk1", "stk2"]
  	paddingOuter: 0.05
  	paddingInner: 0.95
	}
	{
  	// this scale goes up as high as the highest y1 value of all nodes
  	name: y
  	type: linear
  	range: height
  	domain: {data: "nodes", field: "y1"}
	}
	{
  	// use rawData to ensure the colors stay the same when clicking.
  	name: color
  	type: ordinal
  	range: category
  	domain: {data: "rawData", field: "stk1"}
	}
	{
  	// this scale is used to map internal ids (stk1, stk2) to stack names
  	name: stackNames
  	type: ordinal
  	range: ["Source", "Destination"]
  	domain: ["stk1", "stk2"]
	}
  ]
  axes: [
	{
  	// x axis should use custom label formatting to print proper stack names
  	orient: bottom
  	scale: x
  	encode: {
    	labels: {
      	update: {
        	text: {scale: "stackNames", field: "value"}
      	}
    	}
  	}
	}
	{orient: "left", scale: "y"}
  ]
  marks: [
	{
  	// draw the connecting line between stacks
  	type: path
  	name: edgeMark
  	from: {data: "edges"}
  	// this prevents some autosizing issues with large strokeWidth for paths
  	clip: true
  	encode: {
    	update: {
      	// By default use color of the left node, except when showing traffic
      	// from just one country, in which case use destination color.
      	stroke: [
        	{
          	test: groupSelector && groupSelector.stack=='stk1'
          	scale: color
          	field: stk2
        	}
        	{scale: "color", field: "stk1"}
      	]
      	strokeWidth: {field: "strokeWidth"}
      	path: {field: "path"}
      	// when showing all traffic, and hovering over a country,
      	// highlight the traffic from that country.
      	strokeOpacity: {
        	signal: !groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.9 : 0.3
      	}
      	// Ensure that the hover-selected edges show on top
      	zindex: {
        	signal: !groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0
      	}
      	// format tooltip string
      	tooltip: {
        	signal: datum.stk1 + ' → ' + datum.stk2 + '	' + format(datum.size, ',.0f') + '   (' + format(datum.percentage, '.1%') + ')'
      	}
    	}
    	// Simple mouseover highlighting of a single line
    	hover: {
      	strokeOpacity: {value: 1}
    	}
  	}
	}
	{
  	// draw stack groups (countries)
  	type: rect
  	name: groupMark
  	from: {data: "groups"}
  	encode: {
    	enter: {
      	fill: {scale: "color", field: "grpId"}
      	width: {scale: "x", band: 1}
    	}
    	update: {
      	x: {scale: "x", field: "stack"}
      	y: {field: "scaledY0"}
      	y2: {field: "scaledY1"}
      	fillOpacity: {value: 0.6}
      	tooltip: {
        	signal: datum.grpId + '   ' + format(datum.total, ',.0f') + '   (' + format(datum.percentage, '.1%') + ')'
      	}
    	}
    	hover: {
      	fillOpacity: {value: 1}
    	}
  	}
	}
	{
  	// draw country code labels on the inner side of the stack
  	type: text
  	from: {data: "groups"}
  	// don't process events for the labels - otherwise line mouseover is unclean
  	interactive: false
  	encode: {
    	update: {
      	// depending on which stack it is, position x with some padding
      	x: {
        	signal: scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)
      	}
      	// middle of the group
      	yc: {signal: "(datum.scaledY0 + datum.scaledY1)/2"}
      	align: {signal: "datum.rightLabel ? 'left' : 'right'"}
      	baseline: {value: "middle"}
      	fontWeight: {value: "bold"}
      	// only show text label if the group's height is large enough
      	text: {signal: "abs(datum.scaledY0-datum.scaledY1) > 13 ? datum.grpId : ''"}
    	}
  	}
	}
	{
  	// Create a "show all" button. Shown only when a country is selected.
  	type: group
  	data: [
    	// We need to make the button show only when groupSelector signal is true.
    	// Each mark is drawn as many times as there are elements in the backing data.
    	// Which means that if values list is empty, it will not be drawn.
    	// Here I create a data source with one empty object, and filter that list
    	// based on the signal value. This can only be done in a group.
    	{
      	name: dataForShowAll
      	values: [{}]
      	transform: [{type: "filter", expr: "groupSelector"}]
    	}
  	]
  	// Set button size and positioning
  	encode: {
    	enter: {
      	xc: {signal: "width/2"}
      	y: {value: 30}
      	width: {value: 80}
      	height: {value: 30}
    	}
  	}
  	marks: [
    	{
      	// This group is shown as a button with rounded corners.
      	type: group
      	// mark name allows signal capturing
      	name: groupReset
      	// Only shows button if dataForShowAll has values.
      	from: {data: "dataForShowAll"}
      	encode: {
        	enter: {
          	cornerRadius: {value: 6}
          	fill: {value: "#F5F7FA"}
          	stroke: {value: "#c1c1c1"}
          	strokeWidth: {value: 2}
          	// use parent group's size
          	height: {
            	field: {group: "height"}
          	}
          	width: {
            	field: {group: "width"}
          	}
        	}
        	update: {
          	// groups are transparent by default
          	opacity: {value: 1}
        	}
        	hover: {
          	opacity: {value: 0.7}
        	}
      	}
      	marks: [
        	{
          	type: text
          	// if true, it will prevent clicking on the button when over text.
          	interactive: false
          	encode: {
            	enter: {
              	// center text in the paren group
              	xc: {
                	field: {group: "width"}
                	mult: 0.5
              	}
              	yc: {
                	field: {group: "height"}
                	mult: 0.5
                	offset: 2
              	}
              	align: {value: "center"}
              	baseline: {value: "middle"}
              	fontWeight: {value: "bold"}
              	text: {value: "Show All"}
            	}
          	}
        	}
      	]
    	}
  	]
	}
  ]
  signals: [
	{
  	// used to highlight traffic to/from the same country
  	name: groupHover
  	value: {}
  	on: [
    	{
      	events: @groupMark:mouseover
      	update: "{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}"
    	}
    	{events: "mouseout", update: "{}"}
  	]
	}
	// used to filter only the data related to the selected country
	{
  	name: groupSelector
  	value: false
  	on: [
    	{
      	// Clicking groupMark sets this signal to the filter values
      	events: @groupMark:click!
      	update: "{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}"
    	}
    	{
      	// Clicking "show all" button, or double-clicking anywhere resets it
      	events: [
        	{type: "click", markname: "groupReset"}
        	{type: "dblclick"}
      	]
      	update: "false"
    	}
  	]
	}
  ]
}


%%INDEX%%-Heat Map

%%INDEX%%-Heat Map


Question: not traffic-path:-

%%INDEX%%-Traffic Path

%%INDEX%%-Traffic Path

Count


%%INDEX%%-Traffic Path Note

%%INDEX%%-Traffic Path Note

| Traffic Path | Note |
| --|--|
| 1 | Through another resource in the same VPC |
| 2 |  Through an internet gateway or a gateway VPC endpoint |
| 3 |  Through a virtual private gateway |
| 4 |  Through an intra-region VPC peering connection |
| 5 | Through an inter-region VPC peering connection |
| 6 |  Through a local gateway |
| 7 | Through a gateway VPC endpoint (Nitro-based instances only) |
| 8 | Through an internet gateway (Nitro-based instances only) |


account-id vpc-id flow-direction action protocol-code srcaddr srcport dstaddr dstport bytes packets log-status

%%INDEX%%-Search


Global Filters

Global Filters

Total Requests

Total Requests

Request History

Request History

Requests by VPC ID

Requests by VPC ID

Total Requests By Action

Total Requests By Action

Total Bytes

Total Bytes

Total Packets

Total Packets

Requests by Direction

Requests by Direction

Requests by Direction

Requests by Direction

Requests By Type

Requests By Type

Top Source Bytes

Top Source Bytes

Top Destination Bytes

Top Destination Bytes

Top Source Requests

Top Source Requests

Top Destination Requests

Top Destination Requests

Requests by Protocol

Requests by Protocol

Requests by Status

Requests by Status

Top Source AWS Services

Top Source AWS Services

Top Destination AWS Services

Top Destination AWS Services

Network Flow

Network Flow

Heat Map

Heat Map

Egress Traffic Path

Egress Traffic Path

Egress Traffic Path Note

Egress Traffic Path Note

%%INDEX%%-dashboard