def test_ts_chart_with_publish_label_options_happy(): opts = PublishLabelOptions( 'somelabel', y_axis=1, palette_index=PaletteColor.mountain_green, plot_type=PlotType.area_chart, display_name='lol', value_prefix='hi', value_suffix='weee', value_unit='hithere') chart = TimeSeriesChart().with_publish_label_options(opts) assert chart.chart_options['publishLabelOptions'] == [opts.to_dict()]
def test_ts_chart_with_publish_label_options(): """'Legacy' behavior, verified still working.""" opts = PublishLabelOptions( 'somelabel', 0, PaletteColor.mountain_green, PlotType.area_chart, 'foo' ) chart = TimeSeriesChart().with_publish_label_options(opts) assert chart.chart_options['publishLabelOptions'] == [opts.to_dict()]
def test_ts_chart_with_publish_label_options_missing_option(arg): """Test that optional simple keyword arguments can be passed without clobbering each other.""" [(key, value)] = arg.items() opts = PublishLabelOptions('someLabel', **arg).to_dict() assert opts[util.snake_to_camel(key)] == value remaining_values = [x for x in publish_opts_optionals if x is not key] for k in opts.keys(): assert k not in remaining_values
def test_chart_with_empties(value): with pytest.raises(ValueError): Chart().with_name(value) Chart().with_description(value) Chart().with_program() FieldOption(value, False) PublishLabelOptions(value, value, value, value, value)
def test_publish_label_options_invalid_y_axis(): with pytest.raises(ValueError) as ve: PublishLabelOptions( 'somelabel', 2, PaletteColor.mountain_green, PlotType.area_chart, 'foo' ) assert "chart must be 0" in ve.message
def __init__(self, app, env='prod'): super(UserCpuUsedPercentChart, self).__init__() self.with_name('CPU Used % from template class') self.with_description( '% CPU used by type (user, system, i/o, stolen, etc)') self.stack_chart(True) self.with_default_plot_type(PlotType.area_chart) self.with_program(self.__program__(app, env)) self.with_publish_label_options( PublishLabelOptions('A', 0, PaletteColor.hot_pink, PlotType.area_chart, 'User CPU %'))
def test_ts_chart_with_publish_label_options(): opts = PublishLabelOptions('somelabel', 0, PaletteColor.mountain_green, PlotType.area_chart, 'foo') chart = TimeSeriesChart().with_publish_label_options(opts) assert chart.chart_options['publishLabelOptions'] == [opts.to_dict()]
def create_dynamodb_with_stream_charts(table_name, description): """ Create charts for DynamoDB Table that has a Stream enabled. First left chart shows read/write capacity consumed, plus latency. First right chart shows Errors and Throttling on the table. Second left chart shows records returned on the Stream. Second right chart shows errors on the Stream. """ charts = [] charts.extend(create_dynamodb_charts(table_name, description)) charts.append( TimeSeriesChart() \ .with_name("Dynamo Stream " + table_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='ReturnedRecordsCount', palette_index=PaletteColor.green, ) ).with_program( Program( Plot( assigned_name="A", signal_name="ReturnedRecordsCount", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="ReturnedRecordsCount") ) ) ) charts.append( # This chart is usually empty because these kinds of Stream errors don't seem to happen much TimeSeriesChart() \ .with_name("Dynamo Stream " + table_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='SystemErrors', palette_index=PaletteColor.rose, y_axis=1 ) ).with_program( Plot( assigned_name="A", signal_name="SystemErrors", filter=And( Filter("TableName", table_name), Filter("stat", "sum"), Filter("Operation", "GetRecords") # Streams only have 1 operation ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="SystemErrors") ) ) return charts
def create_dynamodb_charts(table_name, description): """ Create charts for DynamoDB Table. Left chart shows read/write capacity consumed, plus latency. Right chart shows Errors and Throttling. """ charts = [] charts.append( TimeSeriesChart() \ .with_name("Dynamo Table " + table_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='ConsumedReadCapacity', palette_index=PaletteColor.green ), PublishLabelOptions( label='ConsumedWriteCapacity', palette_index=PaletteColor.light_green ), PublishLabelOptions( label='Latency', palette_index=PaletteColor.gray, plot_type=PlotType.line_chart, value_unit='Millisecond', y_axis=1 ) ).with_axes([AxisOption(label="Units", min=0), AxisOption(label="Latency", min=0)]) .with_program( Program( Plot( assigned_name="A", signal_name="ConsumedReadCapacityUnits", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="ConsumedReadCapacity" ), Plot( assigned_name="B", signal_name="ConsumedWriteCapacityUnits", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="ConsumedWriteCapacity" ), Plot( assigned_name="C", signal_name="SuccessfulRequestLatency", filter=And( Filter("TableName", table_name), Filter("stat", "mean") ), rollup=RollupType.max, fx=[Mean(by=["TableName", "aws_account_id"])], label="Latency" ) ) ) ) charts.append( TimeSeriesChart() \ .with_name("Dynamo Table " + table_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='ThrottledRequests', palette_index=PaletteColor.rust ), PublishLabelOptions( label='ReadThrottle', palette_index=PaletteColor.tangerine ), PublishLabelOptions( label='WriteThrottle', palette_index=PaletteColor.sunflower ), PublishLabelOptions( label='SystemErrors', palette_index=PaletteColor.rose, y_axis=1 ) ).with_program( Program( Plot( assigned_name="A", signal_name="ThrottledRequests", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="ThrottledRequests" ), Plot( assigned_name="B", signal_name="ReadThrottleEvents", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="ReadThrottle" ), Plot( assigned_name="C", signal_name="WriteThrottleEvents", filter=And( Filter("TableName", table_name), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="WriteThrottle" ), Plot( assigned_name="D", signal_name="SystemErrors", filter=And( Filter("TableName", table_name), Filter("stat", "sum"), Not(Filter("Operation", "GetRecords")) # GetRecords is a Dynamo Stream operation ), rollup=RollupType.sum, fx=[Sum(by=["TableName", "aws_account_id"])], label="SystemErrors") ) ) ) return charts
def create_lambda_charts(function_name, description): """ Create Lambda charts Left chart shows activity and latency. Right chart shows errors, throttles, and iterator age. """ charts = [] charts.append( TimeSeriesChart() \ .with_name("Lambda " + function_name + " Invocations") \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='Invocations', palette_index=PaletteColor.green ), PublishLabelOptions( label='Duration', palette_index=PaletteColor.gray, y_axis=1, plot_type=PlotType.line_chart, value_unit='Millisecond' ) ) .with_axes([AxisOption(label="Count", min=0), AxisOption(label="Latency", min=0)]) .with_program( Program( Plot( assigned_name="A", signal_name="Invocations", filter=And( Filter("FunctionName", function_name), Filter("namespace", "AWS/Lambda"), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "FunctionName"])], label="Invocations"), Plot( assigned_name="B", signal_name="Duration", filter=And( Filter("FunctionName", function_name), Filter("namespace", "AWS/Lambda"), Filter("stat", "mean") ), rollup=RollupType.max, # max rollup is used here so you can still see spikes over longer windows fx=[Sum(by=["aws_account_id", "FunctionName"])], label="Duration") ) ) ) charts.append( TimeSeriesChart() \ .with_name("Lambda " + function_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='Errors', palette_index=PaletteColor.rust ), PublishLabelOptions( label='Throttles', palette_index=PaletteColor.sunflower ), PublishLabelOptions( label='IteratorAge', value_unit='Millisecond', plot_type=PlotType.area_chart, palette_index=PaletteColor.slate_blue, y_axis=1 ) ).with_axes([AxisOption(label="Count", min=0), AxisOption(label="Age", min=0, max=(1000 * 60 * 60 * 36))]) .with_program( Program( Plot( assigned_name="B", signal_name="Errors", filter=And( Filter("FunctionName", function_name), Filter("namespace", "AWS/Lambda"), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "FunctionName"])], label="Errors"), Plot( assigned_name="C", signal_name="Throttles", filter=And( Filter("FunctionName", function_name), Filter("namespace", "AWS/Lambda"), Filter("stat", "sum") ), rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "FunctionName"])], label="Throttles"), Plot( assigned_name="D", signal_name="IteratorAge", filter=And( Filter("FunctionName", function_name), Filter("Resource", function_name), Filter("namespace", "AWS/Lambda"), Filter('stat', 'upper') ), rollup=RollupType.max, # max rollup is used here so you can still see spikes over longer windows # Max here is just to get rid of bad extra metric in Sfx fx=[Max(by=["aws_account_id", "FunctionName"])], label="IteratorAge") ) ) ) return charts
def create_sqs_charts(queue_name, description): """ Create SQS charts Left chart shows messages sent/deleted and number visible. Right chart shows deadletter queue and age of oldest message. """ charts = [] filter = And(Filter("QueueName", queue_name), Filter("namespace", "AWS/SQS"), Filter("stat", "sum")) charts.append( TimeSeriesChart() \ .with_name("SQS " + queue_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='NumberOfMessagesSent', palette_index=PaletteColor.green ), PublishLabelOptions( label='NumberOfMessagesDeleted', palette_index=PaletteColor.light_green ), PublishLabelOptions( label='ApproximateNumberOfMessagesVisible', palette_index=PaletteColor.sky_blue, plot_type=PlotType.line_chart ) ).with_axes([AxisOption(label="Count", min=0)]) .with_program( Program( Plot( assigned_name="A", signal_name="NumberOfMessagesSent", filter=filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "QueueName"])], label="NumberOfMessagesSent"), Plot( assigned_name="B", signal_name="NumberOfMessagesDeleted", filter=filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "QueueName"])], label="NumberOfMessagesDeleted"), Plot( assigned_name="C", signal_name="ApproximateNumberOfMessagesVisible", filter=filter, rollup=RollupType.max, fx=[Max(by=["aws_account_id", "QueueName"])], label="ApproximateNumberOfMessagesVisible") ) ) ) charts.append( TimeSeriesChart() \ .with_name("SQS " + queue_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='DeadLetterMessages', palette_index=PaletteColor.mulberry, y_axis=0 ), PublishLabelOptions( label='ApproximateAgeOfOldestMessage', palette_index=PaletteColor.sunflower, value_unit='Second', plot_type=PlotType.area_chart, y_axis=1 ) ).with_axes([AxisOption(label="Count", min=0), AxisOption(label="Age", min=0)]) .with_program( Program( Plot( assigned_name="A", signal_name="ApproximateNumberOfMessagesVisible", filter=And( # assumes naming convention for DL queues Filter("QueueName", queue_name + "-deadletter", queue_name + "-dlq"), Filter("namespace", "AWS/SQS"), Filter("stat", "upper") ), rollup=RollupType.max, fx=[Sum(by=["aws_account_id", "QueueName"])], label="DeadLetterMessages"), Plot( assigned_name="B", signal_name="ApproximateAgeOfOldestMessage", filter=And( Filter("QueueName", queue_name), Filter("namespace", "AWS/SQS"), Filter("stat", "upper") ), rollup=RollupType.max, # max rollup is used here so you can still see spikes over longer windows fx=[Max(by=["aws_account_id", "QueueName"])], label="ApproximateAgeOfOldestMessage") ) ) ) return charts
def create_kinesis_charts(stream_name, description): """ Create Kinesis charts Left chart shows incoming records and outgoing records. Right chart shows errors, throttles, and iterator age. """ charts = [] sum_filter = And(Filter("StreamName", stream_name), Filter("namespace", "AWS/Kinesis"), Filter("stat", "sum")) charts.append( TimeSeriesChart() \ .with_name("Kinesis Stream " + stream_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='IncomingRecords', palette_index=PaletteColor.green ), PublishLabelOptions( label='GetRecords.Records', palette_index=PaletteColor.light_green ) ).with_axes([AxisOption(label="Count")]) .with_program( Program( Plot( assigned_name="A", signal_name="IncomingRecords", filter=sum_filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "StreamName"])], label="IncomingRecords"), Plot( assigned_name="B", signal_name="GetRecords.Records", filter=sum_filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "StreamName"])], label="GetRecords.Records") ) ) ) charts.append( TimeSeriesChart() \ .with_name("Kinesis Stream " + stream_name) \ .with_description(description) .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) .with_publish_label_options( PublishLabelOptions( label='ReadThroughputExceeded', palette_index=PaletteColor.rust, y_axis=0 ), PublishLabelOptions( label='WriteThroughputExceeded', palette_index=PaletteColor.tangerine, y_axis=0 ), PublishLabelOptions( label='GetRecords.IteratorAge', palette_index=PaletteColor.sunflower, value_unit='Millisecond', plot_type=PlotType.area_chart, y_axis=1 )).with_axes([AxisOption(label="Count"), AxisOption(label="Age")]) .with_program( Program( Plot( assigned_name="A", signal_name="ReadProvisionedThroughputExceeded", filter=sum_filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "StreamName"])], label="ReadThroughputExceeded"), Plot( assigned_name="B", signal_name="WriteProvisionedThroughputExceeded", filter=sum_filter, rollup=RollupType.sum, fx=[Sum(by=["aws_account_id", "StreamName"])], label="WriteThroughputExceeded"), Plot( assigned_name="C", signal_name="GetRecords.IteratorAgeMilliseconds", filter=And( Filter("StreamName", stream_name), Filter("namespace", "AWS/Kinesis"), Filter("stat", "upper") ), rollup=RollupType.max, # max rollup is used here so you can still see spikes over longer windows fx=[Sum(by=["aws_account_id", "StreamName"])], label="GetRecords.IteratorAge") ) ) ) return charts
""" Example 3: make a more advanced chart using more options. This example charts two metrics on the same chart with a different scale for each. """ function_name = 'my-lambda' chart = TimeSeriesChart() \ .with_name("Lambda " + function_name + " Invocations") \ .with_description("") \ .with_default_plot_type(PlotType.column_chart) \ .with_chart_legend_options("sf_metric", show_legend=True) \ .with_publish_label_options( PublishLabelOptions( label='Invocations', palette_index=PaletteColor.green ), PublishLabelOptions( label='Duration', palette_index=PaletteColor.gray, y_axis=1, # right y-axis plot_type=PlotType.line_chart, # override of main chart type for 1 metric value_unit='Millisecond' # SignalFx will automatically convert units to human-readable format ) ) \ .with_axes([ AxisOption(label="Count", min=0), # left Y-axis AxisOption(label="Latency", min=0) # right Y-axis ]) \ .with_program( Program(