systemtap/pcp integration pmda 0.1
David Smith
dsmith@redhat.com
Fri Sep 12 18:37:00 GMT 2014
Here's version 0.1 (up from 0.01!) of my systemtap/pcp integration work
that uses systemtap (https://sourceware.org/systemtap/) to export JSON
data and a pcp (http://www.performancecopilot.org/) python pmda that
reads and processes the JSON data.
At this point things work reasonably well (at least with the test
systemtap script I've attached). There are still lots of "FIXME"
comments spread throughout the code. This time the systemtap side of
things has come along and you no longer have to hand-write JSON to
output data. The script itself is based on some work that Will
Cohen has been doing to measure network latency. Note that the script
does output live data.
The biggest addition this time is array handling, which was a bit
tricky. I'm still not sure the indom handling on the pcp side is correct
(but it seems to follow the other python pmdas).
Here's what live data looks like from pcp:
====
# pminfo -df stap_json
stap_json.json.dummy2
Data Type: string InDom: PM_INDOM_NULL 0xffffffff
Semantics: instant Units: none
value "dummy2"
stap_json.json.dummy_array.dummy2
Data Type: string InDom: 130.1 0x20800001
Semantics: instant Units: none
inst [0 or "1"] value "def"
inst [1 or "0"] value "abc"
inst [2 or "2"] value "ghi"
stap_json.json.dummy_array.dummy1
Data Type: 64-bit int InDom: 130.1 0x20800001
Semantics: counter Units: none
inst [0 or "1"] value 2
inst [1 or "0"] value 1
inst [2 or "2"] value 3
stap_json.json.net_xmit_data.xmit_latency
Data Type: 64-bit int InDom: 130.0 0x20800000
Semantics: counter Units: none
inst [0 or "fake1"] value 0
inst [1 or "fake2"] value 0
inst [2 or "eth0"] value 319
stap_json.json.net_xmit_data.xmit_count
Data Type: 64-bit int InDom: 130.0 0x20800000
Semantics: counter Units: none
inst [0 or "fake1"] value 0
inst [1 or "fake2"] value 0
inst [2 or "eth0"] value 2304551
stap_json.json.read_count
Data Type: 64-bit int InDom: PM_INDOM_NULL 0xffffffff
Semantics: counter Units: none
value 8
stap_json.json.xstring
Data Type: string InDom: PM_INDOM_NULL 0xffffffff
Semantics: instant Units: none
value "testing, 1, 2, 3"
====
The pcp pmda still only supports one systemtap script at this point. I
ran the attached systemtap script using the following command line to
produce the output above.
# stap -m json -v ./net_xmit_json5.stp eth0 fake1 fake2
Any comments/feedback would be appreciated.
--
David Smith
dsmith@redhat.com
Red Hat
http://www.redhat.com
256.217.0141 (direct)
256.837.0057 (fax)
-------------- next part --------------
// This script tracks time between packet queue and xmit.
// The information is provided to userspace via procfs and are read
// using the stap_json PCP PMDA.
// ===========================
// ==== Tapset file start ====
// ===========================
global __json_metric_type, __json_metric_desc
global __json_array_metric_type, __json_array_metric_desc
global __json_metric_output, __json_array_output
function json_add_numeric_metric:long(name:string, description:string)
{
if (name in __json_metric_type)
error(sprintf("Metric '%s' already exists", name))
__json_metric_type[name] = "integer"
__json_metric_desc[name] = description
return 0
}
function json_add_string_metric:long(name:string, description:string)
{
if (name in __json_metric_type)
error(sprintf("Metric '%s' already exists", name))
__json_metric_type[name] = "string"
__json_metric_desc[name] = description
return 0
}
function json_add_array:long(name:string, description:string)
{
if (name in __json_metric_type)
error(sprintf("Metric '%s' already exists", name))
__json_metric_type[name] = "array"
__json_metric_desc[name] = description
# Go ahead and add "__id", which is the array index.
json_add_array_string_metric(name, "__id", "")
return 0
}
function json_add_array_numeric_metric:long(array_name:string,
metric_name:string, metric_description:string)
{
if ([array_name, metric_name] in __json_array_metric_type)
error(sprintf("Array metric '%s' already exists in array %s", metric_name,
array_name))
__json_array_metric_type[array_name, metric_name] = "integer"
__json_array_metric_desc[array_name, metric_name] = metric_description
return 0
}
function json_add_array_string_metric:long(array_name:string,
metric_name:string, metric_description:string)
{
if ([array_name, metric_name] in __json_array_metric_type)
error(sprintf("Array metric '%s' already exists in array %s", metric_name,
array_name))
__json_array_metric_type[array_name, metric_name] = "string"
__json_array_metric_desc[array_name, metric_name] = metric_description
return 0
}
@define __json_output_metric(indent_str, name, type, description)
%(
$value .= sprintf("%s\"%s\": {\n", @indent_str, @name)
$value .= sprintf("%s \"type\": \"%s\",\n", @indent_str, @type)
if (strlen(@description) > 0)
$value .= sprintf("%s \"description\": \"%s\",\n", @indent_str,
@description)
$value .= sprintf("%s \"additionalProperties\": false\n%s}", @indent_str,
@indent_str)
%)
@define __json_output_array(indent_str, name, description)
%(
$value .= sprintf("%s\"%s\": {\n", @indent_str, @name)
$value .= sprintf("%s \"type\": \"array\",\n", @indent_str)
if (strlen(@description) > 0)
$value .= sprintf("%s \"description\": \"%s\",\n", @indent_str,
@description)
$value .= sprintf("%s \"additionalProperties\": false,\n", @indent_str)
$value .= sprintf("%s \"items\": {\n", @indent_str)
$value .= sprintf("%s \"type\": \"object\",\n", @indent_str)
$value .= sprintf("%s \"additionalProperties\": false,\n",
@indent_str)
$value .= sprintf("%s \"properties\": {\n", @indent_str)
__array_comma_needed = 0
foreach ([__array_name, __metric_name] in __json_array_metric_type) {
if (@name == __array_name) {
if (__array_comma_needed)
$value .= ",\n"
__array_comma_needed = 1
__subindent_str = @indent_str . " "
__subtype = __json_array_metric_type[__array_name, __metric_name]
__subdesc = __json_array_metric_desc[__array_name, __metric_name]
@__json_output_metric(__subindent_str, __metric_name, __subtype,
__subdesc)
}
}
$value .= sprintf("\n%s }\n", @indent_str)
$value .= sprintf("%s }\n", @indent_str)
$value .= sprintf("%s}", @indent_str)
%)
@define json_output_schema
%(
# Note: This is the "pretty-printed" version of the schema, intended
# to be read by humans. We could remove the whitespace and newlines
# if we wanted to make the output shorter (but less readable).
#
# Note 2: Note that we have to break this long string into more than
# 1 assignment since we're bumping up against MAXSTRINGLEN. Procfs
# $value can hold more than MAXSTRINGLEN because of the
# '.maxsize(N)' parameter.
$value =
"{\n"
" \"type\": \"object\",\n"
" \"title\": \"root\",\n"
" \"additionalProperties\": false,\n"
" \"properties\": {\n"
" \"generation\": {\n"
" \"type\": \"integer\",\n"
" \"additionalProperties\": false\n"
" },\n"
$value .=
" \"data\": {\n"
" \"type\": \"object\",\n"
" \"additionalProperties\": false,\n"
" \"properties\": {\n"
__comma_needed = 0
foreach (__name in __json_metric_type) {
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
if (__json_metric_type[__name] != "array") {
@__json_output_metric(" ", __name, __json_metric_type[__name],
__json_metric_desc[__name])
}
else {
@__json_output_array(" ", __name, __json_metric_desc[__name])
}
}
$value .=
"\n"
" },\n"
" \"required\": [\n"
__comma_needed = 0
foreach (__name in __json_metric_type) {
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\"", __name)
}
$value .=
"\n"
" ]\n"
" }\n"
" }\n"
"}\n"
%)
# NOTE: This is the "pretty-printed" version of the data, intended
# to be read by humans. We could remove the whitespace and newlines
# if we wanted to make the output shorter (but less readable).
@define json_output_data_start
%(
__comma_needed = 0
$value =
"{\n"
" \"generation\": 1,\n"
" \"data\": {\n"
%)
# Make sure we don't try to output the same metric twice in the same
# data fetch.
@define __json_output_check(name)
%(
if (@name in __json_metric_output)
error(sprintf("Metric '%s' already output", @name))
__json_metric_output[@name] = 1
%)
# Make sure we don't try to output the same array index twice in the same
# data fetch.
@define __json_output_array_check(array_index)
%(
if (@array_index in __json_array_output)
error(sprintf("Array index '%s' already output for array metric %s",
@array_index, __json_array_started))
__json_array_output[@array_index] = 1
%)
# Output a string value.
@define json_output_string_value(name, value)
%(
@__json_output_check(@name)
@__json_output_array_end
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\": \"%s\"", @name, @value)
%)
# Output a numeric value.
@define json_output_numeric_value(name, value)
%(
@__json_output_check(@name)
@__json_output_array_end
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\": %d", @name, @value)
%)
# Output a string value for an array.
@define json_output_array_string_value(array_name, array_index, metric_name, value)
%(
@__json_output_array_start(@array_name, @array_index)
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\": \"%s\"", @metric_name, @value)
%)
# Output a numeric value for an array.
@define json_output_array_numeric_value(array_name, array_index, metric_name,
value)
%(
@__json_output_array_start(@array_name, @array_index)
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\": %d", @metric_name, @value)
%)
# Handle the details of starting the output of an array.
@define __json_output_array_start(array_name, array_index)
%(
if (__json_array_started != @array_name) {
@__json_output_check(@array_name)
@__json_output_array_end
if (__comma_needed)
$value .= ",\n"
__comma_needed = 1
$value .= sprintf(" \"%s\": [\n", @array_name)
$value .= " {\n"
__json_array_started = @array_name
}
if (__json_array_index_started != @array_index) {
@__json_output_array_check(@array_index)
if (__json_array_index_started != "") {
$value .=
"\n"
" },\n"
" {\n"
}
__json_array_index_started = @array_index
$value .= sprintf(" \"__id\": \"%s\"", @array_index)
}
%)
# Handle the details of finishing the output of an array.
@define __json_output_array_end
%(
if (__json_array_started != "") {
$value .=
"\n"
" }\n"
" ]"
__json_array_started = ""
__json_array_index_started = ""
delete __json_array_output
}
%)
# Finish outputting data.
@define json_output_data_end
%(
@__json_output_array_end
$value .=
"\n"
" }\n"
"}\n"
__comma_needed = 0
delete __json_metric_output
%)
probe procfs("schema").read.maxsize(8192)
{
@json_output_schema
}
probe json_data = procfs("data").read.maxsize(8192)
{
}
// =========================
// ==== Tapset file end ====
// =========================
global net_devices
global read_count
probe json_data
{
@json_output_data_start
@json_output_string_value("xstring", "testing, 1, 2, 3")
@json_output_numeric_value("read_count", read_count)
read_count++
foreach (dev in net_devices) {
if (@count(skb_queue_t[dev])) {
@json_output_array_numeric_value("net_xmit_data", dev, "xmit_count",
@sum(skb_queue_t[dev]))
@json_output_array_numeric_value("net_xmit_data", dev, "xmit_latency",
@count(skb_queue_t[dev]))
}
else {
@json_output_array_numeric_value("net_xmit_data", dev, "xmit_count", 0)
@json_output_array_numeric_value("net_xmit_data", dev, "xmit_latency", 0)
}
}
# Add dummy values just to test the interface
@json_output_array_numeric_value("dummy_array", "0", "dummy1", 1)
@json_output_array_string_value("dummy_array", "0", "dummy2", "abc")
@json_output_array_numeric_value("dummy_array", "1", "dummy1", 2)
@json_output_array_string_value("dummy_array", "1", "dummy2", "def")
@json_output_array_numeric_value("dummy_array", "2", "dummy1", 3)
@json_output_array_string_value("dummy_array", "2", "dummy2", "ghi")
@json_output_string_value("dummy2", "dummy2")
@json_output_data_end
}
// Set up the metrics
probe begin
{
// fallback instance device "eth0" if none specified
if (argc == 0) {
argv[1] = "eth0"
}
// remember all the network devices
for (i = 1; i <= argc; i++) {
dev = argv[i]
net_devices[dev] = i - 1
}
// Add the metrics
json_add_string_metric("xstring", "Test string")
json_add_numeric_metric("read_count", "Times values read")
json_add_array("net_xmit_data", "Network transmit data indexed by ethernet device")
json_add_array_numeric_metric("net_xmit_data", "xmit_count", "number of packets for xmit device")
json_add_array_numeric_metric("net_xmit_data", "xmit_latency", "sum of latency for xmit device")
// Add some dummy metrics just to test the tapset.
json_add_array("dummy_array", "")
json_add_array_numeric_metric("dummy_array", "dummy1", "")
json_add_array_string_metric("dummy_array", "dummy2", "")
json_add_string_metric("dummy2", "Test string")
}
// probes to track the information
global skb_queue_start_t, skb_queue_t
probe kernel.trace("net_dev_queue") {
skb_queue_start_t[$skb] = gettimeofday_ns();
}
probe kernel.trace("net_dev_start_xmit"), kernel.trace("net_dev_xmit") {
t = gettimeofday_ns();
st = skb_queue_start_t[$skb]
if (st){
skb_queue_t[kernel_string($dev->name)] <<< t - st
delete skb_queue_start_t[$skb]
}
}
-------------- next part --------------
#!/usr/bin/python
import json
import jsonschema
import collections
from pcp.pmda import PMDA, pmdaMetric, pmdaIndom, pmdaInstid
import cpmapi as c_api
from pcp.pmapi import pmUnits, pmContext as PCP
from ctypes import c_int, POINTER, cast
class Metric(object):
def __init__(self, name):
self.name = name
self.desc = ''
self.type = c_api.PM_TYPE_UNKNOWN
self.sem = c_api.PM_SEM_INSTANT
self.pmid = None
self.obj = None
self.indom = c_api.PM_INDOM_NULL
class Indom(object):
def __init__(self):
self.obj = None
self.values = {}
def add_value(self, name, value):
# PMDA.replace_indom() wants a dictionary, indexed by
# indom string value. PMDA.replace_indom() doesn't really
# care what is stored at that string value. We're storing the
# array index there.
self.values[name] = c_int(value)
class STAP_JSON_PMDA(PMDA):
def __init__(self, pmda_name, domain):
self.pmda_name = pmda_name
PMDA.__init__(self, self.pmda_name, domain)
# Load the schema and data.
self.metrics = {}
self.load_json_schema()
self.load_json_data()
# Make sure the data fits the schema.
jsonschema.validate(self.json_data, self.schema)
# Update the indom list.
self.indoms = {}
self.refresh()
# Parse the schema header, looking for the 'root' name of the
# data (all metrics get created under this name) and create
# the metrics as needed.
#
# FIXME: later this will be the module name. For now, hardcode
# it to 'json'.
self.root_name = "json"
self._parse_schema()
self.set_fetch(self._fetch)
self.set_fetch_callback(self._fetch_callback)
self.set_store_callback(self._store_callback)
def load_json_schema(self):
# Load schema
f = open("/proc/systemtap/json/schema")
try:
self.schema = json.load(f, object_pairs_hook=collections.OrderedDict)
except:
self.schema = {}
f.close()
def load_json_data(self):
# Load data
f = open("/proc/systemtap/json/data")
try :
self.json_data = json.load(f,
object_pairs_hook=collections.OrderedDict)
except:
self.json_data = {}
f.close()
def refresh(self):
# Notice we never delete indoms, we just keep adding.
for array_name in self.indoms.keys():
index = 0
try:
# json_data['data'][array_name] is a list of
# dictionaries.
for item in self.json_data['data'][array_name]:
self.indoms[array_name].add_value(item['__id'], index)
index += 1
except:
pass
self.replace_indom(self.indoms[array_name].obj,
self.indoms[array_name].values)
def _add_metric(self, metric_info):
metric_info.pmid = self.pmid(0, self.metric_idx)
# FIXME: we'll need to handle units/scale at some point...
metric_info.obj = pmdaMetric(metric_info.pmid, metric_info.type,
metric_info.indom, metric_info.sem,
pmUnits(0, 0, 0, 0, 0, 0))
self.add_metric("%s.%s.%s" % (self.pmda_name, self.root_name,
metric_info.name),
metric_info.obj, metric_info.desc)
self.metrics[self.metric_idx] = metric_info
self.metric_idx += 1
def _parse_array_schema(self, array_name, properties):
# First process the array schema "header" information.
array_properties = None
for (key, value) in properties.items():
# 'type' (required): Sanity check it.
if key == 'type':
if not isinstance(value, unicode):
raise TypeError
if value != 'object':
raise TypeError, \
("Type attribute has unknown value '%s'" % value)
# 'additionalProperties' (optional): Ignore it.
elif key == "additionalProperties":
# Do nothing.
pass
# 'properties' (required): Type check it and save for later.
elif key == "properties":
if not isinstance(value, dict):
raise TypeError
array_properties = value
# For everything else, raise an error.
else:
raise RuntimeError, "Unknown attribute '%s'" % key
if not array_properties:
raise RuntimeError, "Schema has no 'properties' attribute"
if not self.indoms.has_key(array_name):
# Note that we're creating an indom here, but we don't
# know any values for it yet. We'll get those on a data
# read.
self.indoms[array_name] = Indom()
self.indoms[array_name].obj = self.indom(self.indom_idx)
self.indom_idx += 1
# If we're here, we know the array "header" was
# reasonable. Now process "properties", which is the real data
# description.
for (name, attributes) in array_properties.items():
metric_info = Metric("%s.%s" % (array_name, name))
metric_info.indom = self.indoms[array_name].obj
for (key, value) in attributes.items():
# 'type' (required): Sanity check it and save it.
if key == 'type':
if not isinstance(value, unicode):
raise TypeError
if value == 'string':
metric_info.type = c_api.PM_TYPE_STRING
metric_info.sem = c_api.PM_SEM_INSTANT
elif value == 'integer':
metric_info.type = c_api.PM_TYPE_64
metric_info.sem = c_api.PM_SEM_COUNTER
else:
raise TypeError, \
("Type attribute has unknown value '%s'" % value)
# 'description' (optional): Type check it and save it.
elif key == 'description':
if not isinstance(value, unicode):
raise TypeError
metric_info.desc = value
# 'additionalProperties' (optional): Ignore it.
elif key == "additionalProperties":
# Do nothing.
pass
# For everything else, raise an error.
else:
raise RuntimeError, \
("Schema for '%s' has an unknown attribute '%s'"
% (name, key))
# Make sure we have everything we need.
if metric_info.type == c_api.PM_TYPE_UNKNOWN:
raise RuntimeError, ("Schema for '%s' has no 'type' attribute"
% name)
# Add the metric (if it isn't our special '__id' metric).
if name != '__id':
self._add_metric(metric_info)
def _parse_schema(self):
'''
Go through the schema, looking for information we can use to create
the pcp representation of the schema. Note that we don't support
every possible JSON schema, we're looking for certain items.
Refer to the following link for details of JSON schemas:
<http://tools.ietf.org/html/draft-zyp-json-schema-03>
'''
# First process the schema "header" information.
data_header = None
for (key, value) in self.schema.items():
# 'type' (required): Just sanity check it.
if key == "type":
if not isinstance(value, unicode) or value != "object":
raise TypeError
# 'title' (optional): Type check it.
elif key == "title":
if not isinstance(value, unicode):
raise TypeError
# 'description' (optional): Type check it.
elif key == "description":
if not isinstance(value, unicode):
raise TypeError
# 'additionalProperties' (optional): Ignore it.
elif key == "additionalProperties":
# Do nothing.
pass
# 'properties' (required): Type check it and save for later.
elif key == "properties":
if not isinstance(value, dict):
raise TypeError
data_header = value
# For everything else, raise an error.
else:
raise RuntimeError, "Unknown attribute '%s'" % key
# Pick the right field for the root of the namespace - prefer
# "title" over "description".
#if self.schema.has_key("title"):
# self.root_name = self.schema["title"]
#elif self.schema.has_key("description"):
# self.root_name = self.schema["description"]
#else:
# raise RuntimeError, "No 'title' or 'description' field in schema header"
# If we're here, we know the "header" was reasonable. Now process
# "properties", which is the data "header".
if not data_header:
raise RuntimeError, "Schema has no 'properties' attribute"
data_properties = None
for (key, value) in data_header.items():
# 'generation' (required): Just sanity check it.
if key == "generation":
if not isinstance(value, dict):
raise TypeError
# 'data' (required): Type check it.
elif key == "data":
if not isinstance(value, dict) \
or not value.has_key("properties") \
or not isinstance(value["properties"], dict):
raise TypeError
data_properties = value["properties"]
# For everything else, raise an error.
else:
raise RuntimeError, "Unknown attribute '%s'" % key
# If we're here, we know the data "header" was reasonable. Now process
# "properties.data.properties", which is the real data description.
if not data_properties:
raise RuntimeError, "Schema has no 'properties.data.properties' attribute"
self.metric_idx = 0
self.indom_idx = 0
for (name, attributes) in data_properties.items():
metric_info = Metric(name)
for (key, value) in attributes.items():
# 'type' (required): Sanity check it and save it.
if key == 'type':
if not isinstance(value, unicode):
raise TypeError
if value == 'string':
metric_info.type = c_api.PM_TYPE_STRING
metric_info.sem = c_api.PM_SEM_INSTANT
elif value == 'integer':
metric_info.type = c_api.PM_TYPE_64
metric_info.sem = c_api.PM_SEM_COUNTER
elif value == 'array':
# For arrays, we have to create metrics for
# each subitem in the array, using the same
# indom. This happens in the 'items' handling
# below.
metric_info.type = c_api.PM_TYPE_NOSUPPORT
else:
raise TypeError, \
("Type attribute has unknown value '%s'" % value)
# 'description' (optional): Type check it and save it.
elif key == 'description':
if not isinstance(value, unicode):
raise TypeError
metric_info.desc = value
# 'additionalProperties' (optional): Ignore it.
elif key == "additionalProperties":
# Do nothing.
pass
# 'default' (optional): Ignore it (for now).
elif key == "default":
# Do nothing for now.
pass
elif key == "items":
if metric_info.type != c_api.PM_TYPE_NOSUPPORT:
raise RuntimeError, \
("Schema has an 'items' item for non-array '%s'"
% name)
# If we're here, we're processing an array's
# schema. For arrays, we have to create metrics for
# each subitem in the array, using the same
# indom.
self._parse_array_schema(name, value)
# For everything else, raise an error.
else:
raise RuntimeError, \
("Schema for '%s' has an unknown attribute '%s'"
% (name, key))
# Make sure we have everything we need.
if metric_info.type == c_api.PM_TYPE_UNKNOWN:
raise RuntimeError, ("Schema for '%s' has no 'type' attribute"
% name)
# Add the metric.
if metric_info.type != c_api.PM_TYPE_NOSUPPORT:
self._add_metric(metric_info)
def _fetch(self):
''' Called once per "fetch" PDU, before callbacks '''
self.load_json_data()
self.refresh()
def _fetch_callback(self, cluster, item, inst):
'''
Main fetch callback. Returns a list of value,status (single
pair) for requested pmid/inst.
'''
if cluster != 0:
return [c_api.PM_ERR_PMID, 0]
try:
metric_info = self.metrics[item]
except:
return [c_api.PM_ERR_PMID, 0]
# Handle array metrics.
if metric_info.indom != c_api.PM_INDOM_NULL:
# Get the array index from the indom.
voidp = self.inst_lookup(metric_info.indom, inst)
if voidp == None:
return [c_api.PM_ERR_INST, 0]
array_indexp = cast(voidp, POINTER(c_int))
array_index = array_indexp.contents.value
# Split the full name into the array name and metric
(array, metric) = metric_info.name.split('.', 2)
try:
return [self.json_data['data'][array][array_index][metric], 1]
except:
pass
# Handle single-valued metrics.
else:
try:
return [self.json_data['data'][metric_info.name], 1]
except:
pass
return [c_api.PM_ERR_TYPE, 0]
def _store_callback(self, cluster, item, inst, val):
'''
Store callback, executed when a request to write to a metric
happens. Returns a single value.
'''
# Since we don't support storing values, always fail.
return c_api.PM_ERR_PERMISSION
if __name__ == '__main__':
STAP_JSON_PMDA('stap_json', 130).run()
-------------- next part --------------
{
"generation": 1,
"data": {
"xstring": "testing, 1, 2, 3",
"read_count": 9,
"net_xmit_data": [
{
"__id": "eth0",
"xmit_count": 7699136,
"xmit_latency": 1109
},
{
"__id": "fake1",
"xmit_count": 0,
"xmit_latency": 0
},
{
"__id": "fake2",
"xmit_count": 0,
"xmit_latency": 0
}
],
"dummy_array": [
{
"__id": "0",
"dummy1": 1,
"dummy2": "abc"
},
{
"__id": "1",
"dummy1": 2,
"dummy2": "def"
},
{
"__id": "2",
"dummy1": 3,
"dummy2": "ghi"
}
],
"dummy2": "dummy2"
}
}
-------------- next part --------------
{
"type": "object",
"title": "root",
"additionalProperties": false,
"properties": {
"generation": {
"type": "integer",
"additionalProperties": false
},
"data": {
"type": "object",
"additionalProperties": false,
"properties": {
"xstring": {
"type": "string",
"description": "Test string",
"additionalProperties": false
},
"read_count": {
"type": "integer",
"description": "Times values read",
"additionalProperties": false
},
"net_xmit_data": {
"type": "array",
"description": "Network transmit data indexed by ethernet device",
"additionalProperties": false,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"__id": {
"type": "string",
"additionalProperties": false
},
"xmit_count": {
"type": "integer",
"description": "number of packets for xmit device",
"additionalProperties": false
},
"xmit_latency": {
"type": "integer",
"description": "sum of latency for xmit device",
"additionalProperties": false
}
}
}
},
"dummy_array": {
"type": "array",
"additionalProperties": false,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"__id": {
"type": "string",
"additionalProperties": false
},
"dummy1": {
"type": "integer",
"additionalProperties": false
},
"dummy2": {
"type": "string",
"additionalProperties": false
}
}
}
},
"dummy2": {
"type": "string",
"description": "Test string",
"additionalProperties": false
}
},
"required": [
"xstring",
"read_count",
"net_xmit_data",
"dummy_array",
"dummy2"
]
}
}
}
More information about the Systemtap
mailing list