{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Observability Solution from CloudWatch: Apache Tomcat on EC2. Version: 1.0.0.",
  "Transform": "AWS::LanguageExtensions",
  "Parameters": {
    "DashboardNameParameter": {
      "Type": "String",
      "Description": "Enter name of the dashboard, the maximum length is 255, and valid characters are A-Z, a-z, 0-9, \"-\", and \"_\". The dashboard will display metrics from the region where the stack is being created. To easily differentiate this dashboard from similar ones in other regions, we recommend including the region name in the dashboard name.",
      "MinLength": "1",
      "MaxLength": "255",
      "AllowedPattern": "^[a-zA-Z0-9-_]*$",
      "Default": "TomcatDashboard"
    }
  },
  "Resources": {
    "CloudWatchDashboard": {
      "Type": "AWS::CloudWatch::Dashboard",
      "Properties": {
        "DashboardName": {
          "Ref": "DashboardNameParameter"
        },
        "DashboardBody": {
          "Fn::ToJsonString": {
            "variables": [
              {
                "type": "pattern",
                "pattern": "TomcatApp",
                "inputType": "select",
                "id": "TomcatApp",
                "label": "Tomcat App",
                "defaultValue": "__FIRST",
                "visible": true,
                "search": "{CWAgent,AppName,InstanceId} MetricName=tomcat.sessions",
                "populateFrom": "AppName"
              }
            ],
            "widgets": [
              {
                "height": 8,
                "width": 8,
                "y": 11,
                "x": 16,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "MAX(usage)",
                        "id": "max",
                        "period": 60,
                        "label": "Max Used [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(usage)",
                        "id": "avg",
                        "period": 60,
                        "label": "Average Used [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.used\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "usage",
                        "period": 60,
                        "label": "Heap Usage",
                        "visible": false
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Application heap memory usage"
                }
              },
              {
                "height": 3,
                "width": 24,
                "y": 0,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "# App overview\n\nThis part of the dashboard gives you a high-level summary and overall picture of your selected Tomcat App and selected duration using metrics aggregated from all instances in your cluster. \n\n**Note**: View data from different Tomcat Apps using the `Tomcat App` dropdown at the top of the dashboard.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 3,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SUM(errors)",
                        "id": "e1",
                        "period": 60,
                        "label": "Total Errors [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}]"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(errors)",
                        "id": "e2",
                        "period": 60,
                        "label": "Average Errors [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler} MetricName=\"tomcat.errors\" AppName=\"TomcatApp\"', 'Sum', 60)",
                        "id": "errors",
                        "period": 60,
                        "label": "Errors",
                        "visible": false
                      }
                    ]
                  ],
                  "sparkline": true,
                  "view": "timeSeries",
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Application request errors",
                  "stacked": false,
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 3,
                "x": 8,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SUM(requests)",
                        "id": "e1",
                        "period": 60,
                        "label": "Total Requests [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}]"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(requests)",
                        "id": "e2",
                        "period": 60,
                        "label": "Average Requests [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler} MetricName=\"tomcat.request_count\" AppName=\"TomcatApp\"', 'Sum', 60)",
                        "id": "requests",
                        "period": 60,
                        "label": "Requests",
                        "visible": false
                      }
                    ]
                  ],
                  "sparkline": true,
                  "view": "timeSeries",
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Application requests",
                  "stacked": false,
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 3,
                "x": 16,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "100 * (errors_sum/denominator_sum)",
                        "label": "Total Error Rate [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]",
                        "id": "error_rate_sum",
                        "period": 60
                      }
                    ],
                    [
                      {
                        "expression": "SUM(err)",
                        "id": "errors_sum",
                        "label": "Sum of all errors across instances and proto_handlers",
                        "period": 60,
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SUM(req)",
                        "id": "requests_sum",
                        "label": "Sum of all requests across instances and proto_handlers",
                        "period": 60,
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "IF(requests_sum>1,requests_sum, 1)",
                        "label": "denominator normalizer",
                        "id": "denominator_sum",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler} MetricName=\"tomcat.errors\" AppName=\"TomcatApp\"', 'Sum', 60)",
                        "id": "err",
                        "label": "errors",
                        "period": 60,
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler} MetricName=\"tomcat.request_count\" AppName=\"TomcatApp\"', 'Sum', 60)",
                        "id": "req",
                        "label": "requests",
                        "period": 60,
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Application request error rate",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Percent",
                      "min": 0,
                      "max": 100
                    }
                  },
                  "singleValueFullPrecision": false,
                  "stacked": false
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 11,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "MAX(SEARCH('{CWAgent,AppName,InstanceId,proto_handler} MetricName=\"tomcat.max_time\" AppName=\"TomcatApp\"', 'Maximum', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Max Time"
                      }
                    ]
                  ],
                  "sparkline": true,
                  "view": "singleValue",
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Max application request processing time milliseconds",
                  "stacked": false,
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Milliseconds"
                    }
                  }
                }
              },
              {
                "height": 3,
                "width": 24,
                "y": 19,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "# Breakdown by server\n\nThe following sections of the dashboard give you a more detailed look at the top contributing servers for different Tomcat App metrics. \n\n**Note**: View data from different Tomcat Apps using the `Tomcat App` dropdown at the top of the dashboard.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 24,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(errors, MAX, DESC, 10)",
                        "label": "Errors [min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(errors)",
                        "label": "Average errors of all servers and proto_handlers [avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler} AppName=\"TomcatApp\" MetricName=\"tomcat.errors\"', 'Sum', 60))",
                        "label": "Errors",
                        "id": "errors",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "title": "Top 10 request errors by server and proto_handler",
                  "period": 60,
                  "stat": "Average",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 24,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(requests, MAX, DESC, 10)",
                        "label": "Requests [min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(requests)",
                        "label": "Average requests of all servers and proto_handlers [avg: ${AVG}]"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler} AppName=\"TomcatApp\" MetricName=\"tomcat.request_count\"', 'Sum', 60))",
                        "label": "Requests",
                        "id": "requests",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "title": "Top 10 request count by server and proto_handler",
                  "period": 60,
                  "stat": "Average",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 32,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Request processing time\n\n\nThis section displays the total time spent processing requests and the maximum time spent by Tomcat processing a single request. These metrics help identify performance bottlenecks and provide insights into the overall request load on your server. ",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 34,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(time, MAX, DESC, 10)",
                        "period": 60,
                        "label": "Processing Time [min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}",
                        "id": "m1"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(time)",
                        "period": 60,
                        "label": "Average time of all servers and proto_handlers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler} AppName=\"TomcatApp\" MetricName=\"tomcat.processing_time\"', 'Sum', 60))",
                        "period": 60,
                        "label": "Processing time",
                        "visible": false,
                        "id": "time"
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "period": 60,
                  "stat": "p99",
                  "title": "Top 10 total time to process requests by server and proto_handler",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Milliseconds",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 34,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(time, MAX, DESC, 10)",
                        "period": 60,
                        "label": "Max Time [last: ${LAST}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}",
                        "id": "m1"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(time)",
                        "period": 60,
                        "label": "Average time of all servers and proto_handlers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler} AppName=\"TomcatApp\" MetricName=\"tomcat.max_time\"', 'Maximum', 60))",
                        "period": 60,
                        "label": "Max time",
                        "visible": false,
                        "id": "time"
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Maximum",
                  "title": "Top 10 request max processing time by server and proto_handler",
                  "period": 60,
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Milliseconds",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 60,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Network traffic\n\n\nThis section displays the amount of data sent and received by Tomcat over the network. The metrics help you monitor the network traffic load on your server and identify potential bottlenecks or saturation points.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 62,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(traffic, MAX, DESC, 10)",
                        "label": "Sent Traffic [min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(traffic)",
                        "label": "Average sent traffic of all servers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler,direction} direction=\"sent\" AppName=\"TomcatApp\" MetricName=\"tomcat.traffic\"', 'Sum', 60))",
                        "label": "Sent Traffic",
                        "id": "traffic",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "period": 60,
                  "title": "Top 10 sent traffic by server and proto_handler",
                  "stat": "Average",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Bytes",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 62,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(traffic, MAX, DESC, 10)",
                        "label": "Received Traffic [min: ${MIN}, max: ${MAX}, avg: ${AVG}, sum: ${SUM}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(traffic)",
                        "label": "Average received traffic of all servers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler,direction} direction=\"received\" AppName=\"TomcatApp\" MetricName=\"tomcat.traffic\"', 'Sum', 60))",
                        "label": "Received Traffic",
                        "id": "traffic",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "period": 60,
                  "title": "Top 10 received traffic by server and proto_handler",
                  "stat": "Average",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Bytes",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 42,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Sessions and threads\n\n\nThis section provides insights into the thread and session management of your Tomcat server. It displays the number of busy threads and the total current thread count, allowing you to monitor thread utilization and optimize thread pool configurations. This section also displays the number of active sessions, which can help identify potential memory or resource constraints.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 44,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(threads, MAX, DESC, 10)",
                        "period": 60,
                        "label": "Busy Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(threads)",
                        "period": 60,
                        "label": "Average busy threads count of all servers and proto_handlers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler,state} state=\"busy\" AppName=\"TomcatApp\" MetricName=\"tomcat.threads\"', 'Average', 60))",
                        "period": 60,
                        "label": "Busy Threads",
                        "id": "threads",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "period": 60,
                  "stat": "Sum",
                  "title": "Top 10 busy threads by server and proto_handler",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 44,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(threads, MAX, DESC, 10)",
                        "period": 60,
                        "label": "Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}] - ${PROP('Dim.proto_handler')} - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(threads)",
                        "period": 60,
                        "label": "Average threads count of all servers and proto_handlers [avg: ${AVG}]",
                        "id": "avg"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId,proto_handler,state} state=\"idle\" AppName=\"TomcatApp\" MetricName=\"tomcat.threads\"', 'Average', 60))",
                        "period": 60,
                        "label": "Threads",
                        "id": "threads",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "period": 60,
                  "stat": "Sum",
                  "title": "Top 10 current thread count by server and proto_handler",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 52,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(sessions, MAX, DESC, 10)",
                        "label": "Sessions [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]  - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(sessions)",
                        "label": "Average sessions of all servers and proto_handlers [avg: ${AVG}]",
                        "id": "e1"
                      }
                    ],
                    [
                      {
                        "expression": "REMOVE_EMPTY(SEARCH('{CWAgent,AppName,InstanceId} AppName=\"TomcatApp\" MetricName=\"tomcat.sessions\"', 'Average', 60))",
                        "label": "Sessions",
                        "id": "sessions",
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "title": "Top 10 active sessions by server",
                  "period": 60,
                  "stat": "Average",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  }
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 22,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Requests\n\n\nThis section displays the number of errors encountered during request processing and total number of requests processed by Tomcat. Use the error count to identify and troubleshoot potential issues. Additionally, the count metric helps you understand the load on your server.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 11,
                "x": 8,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SUM(all_threads)",
                        "id": "threads_sum",
                        "label": "Total Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]",
                        "period": 60
                      }
                    ],
                    [
                      {
                        "expression": "AVG(all_threads)",
                        "label": "Average Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]",
                        "id": "threads_avg",
                        "period": 60
                      }
                    ],
                    [
                      {
                        "expression": "SUM(busy_threads)",
                        "id": "busy_threads_sum",
                        "label": "Total Busy Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]",
                        "period": 60
                      }
                    ],
                    [
                      {
                        "expression": "AVG(busy_threads)",
                        "label": "Average Busy Threads Count [last: ${LAST}, min: ${MIN}, max: ${MAX}, avg: ${AVG}]",
                        "id": "busy_threads_avg",
                        "period": 60
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler,state} state=\"busy\" MetricName=\"tomcat.threads\" AppName=\"TomcatApp\"', 'Average', 60)",
                        "id": "busy_threads",
                        "label": "Busy Threads",
                        "period": 60,
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SEARCH('{CWAgent,AppName,InstanceId,proto_handler,state} state=\"idle\" MetricName=\"tomcat.threads\" AppName=\"TomcatApp\"', 'Average', 60)",
                        "id": "all_threads",
                        "label": "All Threads",
                        "period": 60,
                        "visible": false
                      }
                    ]
                  ],
                  "view": "timeSeries",
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Application thread count",
                  "yAxis": {
                    "left": {
                      "showUnits": false,
                      "label": "Count",
                      "min": 0
                    }
                  },
                  "singleValueFullPrecision": false,
                  "stacked": false
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 70,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "# JVM host metrics\nThe following sections provide a more detailed look at the top contributing servers for various JVM metrics, in your selected JVM process group.",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 74,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.used\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Used [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.used\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Used [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 heap memory used"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 92,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.threads.count\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Threads Count [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.threads.count\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Threads Count [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Count",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 threads count"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 92,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.classes.loaded\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Classes Loaded [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.classes.loaded\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Classes Loaded [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Count",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 classes loaded"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 82,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.used\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Used [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.used\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Used [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 non-heap memory used"
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 72,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Memory usage by host\nThis section provides visibility into the memory usage of hosts in the selected JVM process group. Heap usage metrics help you identify memory leaks and manage memory allocation issues. The non-heap metrics are crucial for monitoring the performance of the JVM.\nWhen maximum heap memory or non-heap memory displays as negative, it means that the maximum is not configured and the metric emits -1 for that metric.",
                  "background": "transparent"
                }
              },
              {
                "height": 2,
                "width": 24,
                "y": 90,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Threads and classes loaded by host\nThis section provides visibility into the threads and classes loaded of hosts on the selected JVM process group. An unexpected high number of threads can indicate issues such as thread leaks or high concurrency demands. The number of classes loaded can help detect excessive dynamic class creation.",
                  "background": "transparent"
                }
              },
              {
                "height": 3,
                "width": 24,
                "y": 100,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "## Garbage collection\nThis section provides visibility into the garbage collection of hosts on the selected JVM process group. Use the number of garbage collections to monitor memory issues or suboptimal JVM settings. High garbage collection time might indicate that the JVM is struggling to free memory efficiently.\nThe heap is partitioned into a set of equal-sized heap regions, each a contiguous range of virtual memory with no fixed size for Eden, Survivor, or Old. This provides greater flexibility and efficiency. G1 (Garbage first) performs a concurrent global marking phase to determine the liveness of objects throughout the heap.\nMinor GC moves the live objects from Eden to Survivor 1 (or Survivor 2) when Eden memory exceeds its limit. In a mixed garbage collection, the G1 GC optionally adds some old regions to the set of eden and survivor regions that will be collected. The exact number of old regions added is controlled by a number of flags. Full GC performs in-place compaction of the entire heap and might be slow. Full garbage collections are still single threaded, but if tuned properly your applications should avoid full garbage collections.\n",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 113,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.count\" ProcessGroupName=\"TomcatApp\" name=\"G1 Young Generation\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Count",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Invocations Per Minute [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Invocations [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Count",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection invocations per minute"
                }
              },
              {
                "height": 1,
                "width": 24,
                "y": 103,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "### G1 concurrent garbage collection invocations and duration",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 113,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.elapsed\" ProcessGroupName=\"TomcatApp\" name=\"G1 Young Generation\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Duration",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Duration [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Duration [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Milliseconds",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection duration"
                }
              },
              {
                "height": 1,
                "width": 24,
                "y": 112,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "### Minor garbage collection invocations and duration",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 104,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.count\" ProcessGroupName=\"TomcatApp\" name=\"G1 Concurrent GC\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Count",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Invocations Per Minute [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Invocations [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Count",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection invocations per minute"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 104,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.elapsed\" ProcessGroupName=\"TomcatApp\" name=\"G1 Concurrent GC\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Duration",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Duration [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Duration [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Milliseconds",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection duration"
                }
              },
              {
                "height": 1,
                "width": 24,
                "y": 121,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": "### Mixed garbage collection invocations and duration",
                  "background": "transparent"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 122,
                "x": 0,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.count\" ProcessGroupName=\"TomcatApp\" name=\"G1 Old Generation\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Count",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Invocations Per Minute [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Invocations [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Count",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection invocations per minute"
                }
              },
              {
                "height": 8,
                "width": 12,
                "y": 122,
                "x": 12,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SEARCH('{CWAgent,InstanceId,ProcessGroupName,name} MetricName=\"jvm.gc.collections.elapsed\" ProcessGroupName=\"TomcatApp\" name=\"G1 Old Generation\"', 'Sum', 60)",
                        "id": "e2",
                        "period": 60,
                        "label": "GC Duration",
                        "visible": false
                      }
                    ],
                    [
                      {
                        "expression": "SORT(e2, MAX, DESC, 10)",
                        "label": "Duration [last: ${LAST}, max: ${MAX}, sum: ${SUM}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(e2)",
                        "label": "Average Duration [avg: ${AVG}]",
                        "id": "m2"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Milliseconds",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 garbage collection duration"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 74,
                "x": 8,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.committed\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Committed [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.committed\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Committed [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 heap memory committed"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 74,
                "x": 16,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.max\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Max [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.heap.max\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Max [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 heap memory max"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 82,
                "x": 8,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.committed\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Committed [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.committed\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Committed [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false,
                      "min": 0
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 non-heap memory committed"
                }
              },
              {
                "height": 8,
                "width": 8,
                "y": 82,
                "x": 16,
                "type": "metric",
                "properties": {
                  "metrics": [
                    [
                      {
                        "expression": "SORT(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.max\" ProcessGroupName=\"TomcatApp\"', 'Average', 60), MAX, DESC, 10)",
                        "id": "m1",
                        "period": 60,
                        "label": "Max [avg: ${AVG}, max: ${MAX}] - ${PROP('Dim.InstanceId')}"
                      }
                    ],
                    [
                      {
                        "expression": "AVG(SEARCH('{CWAgent,InstanceId,ProcessGroupName} MetricName=\"jvm.memory.nonheap.max\" ProcessGroupName=\"TomcatApp\"', 'Average', 60))",
                        "id": "e1",
                        "period": 60,
                        "label": "Average Max [avg: ${AVG}, max: ${MAX}]"
                      }
                    ]
                  ],
                  "yAxis": {
                    "left": {
                      "label": "Bytes",
                      "showUnits": false
                    }
                  },
                  "view": "timeSeries",
                  "stacked": false,
                  "region": {
                    "Ref": "AWS::Region"
                  },
                  "stat": "Average",
                  "period": 60,
                  "title": "Top 10 non-heap memory max"
                }
              },
              {
                "height": 3,
                "width": 24,
                "y": 130,
                "x": 0,
                "type": "text",
                "properties": {
                  "markdown": {
                    "Fn::Join": [
                      "",
                      [
                        "# EC2 metrics\nTo view the AWS/EC2 vended metrics for your EC2 instances, refer to the [Amazon EC2 CloudWatch Automatic Dashboard](https://",
                        {
                          "Ref": "AWS::Region"
                        },
                        ".console.aws.amazon.com/cloudwatch/home?region=",
                        {
                          "Ref": "AWS::Region"
                        },
                        "#home:dashboards/EC2).\n\n\nTo view system-level metrics collected by the CloudWatch agent deployed to your EC2 instances, refer the Monitoring tab for the relevant instance on the [Amazon EC2 console](https://",
                        {
                          "Ref": "AWS::Region"
                        },
                        ".console.aws.amazon.com/ec2/home#Instances)."
                      ]
                    ]
                  },
                  "background": "transparent"
                }
              }
            ]
          }
        }
      }
    }
  }
}