├── .gitignore
├── NOTICE.txt
├── src
├── main
│ ├── java
│ │ └── com
│ │ │ └── appdynamics
│ │ │ └── extensions
│ │ │ └── redis
│ │ │ ├── utils
│ │ │ ├── Constants.java
│ │ │ └── InfoMapExtractor.java
│ │ │ ├── RedisMonitor.java
│ │ │ ├── RedisCommandHandler.java
│ │ │ ├── metrics
│ │ │ ├── CommonMetricsModifier.java
│ │ │ ├── InfoMetrics.java
│ │ │ └── SlowLogMetrics.java
│ │ │ └── RedisMonitorTask.java
│ └── resources
│ │ └── conf
│ │ ├── monitor.xml
│ │ └── config.yml
└── test
│ ├── resources
│ ├── log4j.xml
│ ├── slowlog.txt
│ ├── info.txt
│ └── conf
│ │ └── config.yml
│ └── java
│ └── com
│ └── appdynamics
│ └── extensions
│ └── redis
│ ├── utils
│ └── InfoMapExtractorTest.java
│ └── metrics
│ ├── SlowLogMetricsTest.java
│ └── InfoMetricsTest.java
├── metadata.json
├── USE_CASE.md
├── CHANGELOG.md
├── pom.xml
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | *.iml
3 | .settings
4 | .classpath
5 | .project
6 | *.log
7 | *.ipr
8 | *.iws
9 | .idea
10 | .DS_Store
11 | out/
12 |
13 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Notice and Disclaimer
2 |
3 | All Extensions published by AppDynamics are governed by the Apache License v2 and are excluded from the definition of covered software under any agreement between AppDynamics and the User governing AppDynamics Pro Edition, Test & Dev Edition, or any other Editions.
4 |
--------------------------------------------------------------------------------
/src/main/java/com/appdynamics/extensions/redis/utils/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013. AppDynamics LLC and its affiliates.
3 | * * All Rights Reserved.
4 | * * This is unpublished proprietary source code of AppDynamics LLC and its affiliates.
5 | * * The copyright notice above does not evidence any actual or intended publication of such source code.
6 | */
7 |
8 | package com.appdynamics.extensions.redis.utils;
9 |
10 | public class Constants {
11 | public static final String DEFAULT_METRIC_PREFIX = "Custom Metrics|Redis|";
12 | public static final String METRIC_SEPARATOR = "|";
13 | }
14 |
--------------------------------------------------------------------------------
/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : "redis-monitor",
3 | "type" : "monitor",
4 | "displayName" : "Redis Monitoring Extension",
5 | "description" : "An AppDynamics extension to be used with a stand alone Java machine agent to provide metrics for Redis servers.",
6 | "version" : "2.0.0",
7 | "downloadLink" : "https://github.com/Appdynamics/redis-monitoring-extension/releases/download/v2.0.0/RedisMonitor-2.0.0.zip",
8 | "imageLink" : "https:///www.appdynamics.com/media/uploaded-images/1510098508/.thumbnails/redis-logo-stack-52x0.png",
9 | "configs" : [
10 | {
11 | "name" : "monitor.xml",
12 | "link" : "https://raw.githubusercontent.com/Appdynamics/redis-monitoring-extension/master/src/main/resources/conf/monitor.xml"
13 | },
14 | {
15 | "name" : "config.yml",
16 | "link" : "https://raw.githubusercontent.com/Appdynamics/redis-monitoring-extension/master/src/main/resources/conf/config.yml"
17 | }
18 | ]
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/USE_CASE.md:
--------------------------------------------------------------------------------
1 | # Redis Monitoring Extension for AppDynamics
2 |
3 | Redis is an in memory key-value data store used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries.
4 |
5 | The Redis monitoring extension can monitor multiple Redis servers and display the statistics in AppDynamics Metric Browser.
6 |
7 | ## Related Sandbox
8 |
9 | For reference only (Extension deployment is not possible on the current sandbox) [Cisco AppDynamics sandbox](https://devnetsandbox.cisco.com/RM/Diagram/Index/9e056219-ab84-4741-9485-de3d3446caf2?diagramType=Topology)
10 |
11 | ## Links to DevNet Learning Labs
12 |
13 | [AppDynamics Fundamentals](https://developer.cisco.com/learning/modules/appdynamics-fundamentals)
14 |
15 | [Installation and Configuration workflow](https://github.com/Appdynamics/redis-monitoring-extension/blob/master/README.md)
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/test/resources/slowlog.txt:
--------------------------------------------------------------------------------
1 | 1) 1) (integer) 15
2 | 2) (integer) 1505158204
3 | 3) (integer) 18
4 | 4) 1) "slowlog"
5 | 2) "get"
6 | 2) 1) (integer) 14
7 | 2) (integer) 1505158204
8 | 3) (integer) 45
9 | 4) 1) "slowlog"
10 | 2) "get"
11 | 3) 1) (integer) 13
12 | 2) (integer) 1505158203
13 | 3) (integer) 20
14 | 4) 1) "slowlog"
15 | 2) "get"
16 | 4) 1) (integer) 12
17 | 2) (integer) 1505158203
18 | 3) (integer) 39
19 | 4) 1) "slowlog"
20 | 2) "get"
21 | 5) 1) (integer) 11
22 | 2) (integer) 1505158203
23 | 3) (integer) 34
24 | 4) 1) "slowlog"
25 | 2) "get"
26 | 6) 1) (integer) 10
27 | 2) (integer) 1505158203
28 | 3) (integer) 34
29 | 4) 1) "slowlog"
30 | 2) "get"
31 | 7) 1) (integer) 9
32 | 2) (integer) 1505158202
33 | 3) (integer) 41
34 | 4) 1) "slowlog"
35 | 2) "get"
36 | 8) 1) (integer) 8
37 | 2) (integer) 1505158202
38 | 3) (integer) 30
39 | 4) 1) "slowlog"
40 | 2) "get"
41 | 9) 1) (integer) 7
42 | 2) (integer) 1505158202
43 | 3) (integer) 28
44 | 4) 1) "slowlog"
45 | 2) "get"
46 | 10) 1) (integer) 6
47 | 2) (integer) 1505158201
48 | 3) (integer) 27
49 | 4) 1) "slowlog"
50 | 2) "get"
51 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Redis Monitoring Extension
2 |
3 | ## 3.0.3 - Jan, 2025
4 | 1. Fix a problem with "count="
5 |
6 | ## 3.0.2 - Sept, 2024
7 | 1. Updated ext commons with vulnerability fixes.
8 | 2. Fixed junit vulnerability.
9 |
10 | ## 3.0.1 - Jan, 2021
11 | 1. Updated to new extensions framework(2.2.4).
12 | 2. Fixed issue for global encryptionKey
13 | 3. Fixed issue for heartbeat metric
14 |
15 | ## 3.0.0 - May, 2020
16 | 1. Updated to new extensions framework(2.2.3).
17 | 2. Added the SSL connection ability from the extension.
18 |
19 | ## 2.0.2 - Feb 22, 2019
20 | 1. Fixed the documentation bug in config.yml.
21 |
22 | ## 2.0.1 - Mar 29, 2018
23 | 1. Added copyright, LICENSE.txt and NOTICE.txt.
24 |
25 | ## 2.0.0 - May 27, 2018
26 | 1. Revamped the extension to support new extensions framework(2.0.0).
27 | 2. Added new metrics like "no_of_new_slow_logs", "connectionStatus.
28 |
29 | ## 1.0.7
30 | 1. Fix for includePatterns.
31 |
32 | ## 1.0.6
33 | 1. Added code fixes.
34 |
35 | ## 1.0.5
36 | 1. Added commandstats and keyspace_hit_ratio.
37 |
38 | ## 1.0.4
39 | 1. JDK 1.6 compatible.
40 |
41 | ## 1.0.3
42 | 1. Revamped and Added more metrics.
43 |
44 | ## 1.0.2
45 | 1. Support for role metrics.
46 |
47 | ## 1.0.1
48 | 1. Code Optimization.
49 |
50 | ## 1.0.0
51 | 1. Initial version.
52 |
--------------------------------------------------------------------------------
/src/main/resources/conf/monitor.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | RedisMonitor
10 | managed
11 | true
12 | Monitors a Redis key-value-store server.
13 |
14 |
15 |
16 | RedisMonitor Run Task
17 | RedisMonitor Run Task
18 | RedisMonitor Run Task
19 | java
20 | periodic
21 | 60
22 | 60
23 |
24 |
25 |
26 |
27 |
28 | redis-monitoring-extension.jar
29 | com.appdynamics.extensions.redis.RedisMonitor
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/test/java/com/appdynamics/extensions/redis/utils/InfoMapExtractorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013. AppDynamics LLC and its affiliates.
3 | * * All Rights Reserved.
4 | * * This is unpublished proprietary source code of AppDynamics LLC and its affiliates.
5 | * * The copyright notice above does not evidence any actual or intended publication of such source code.
6 | */
7 |
8 | package com.appdynamics.extensions.redis.utils;
9 |
10 | import org.apache.commons.io.FileUtils;
11 | import org.junit.Assert;
12 | import org.junit.Before;
13 | import org.junit.Test;
14 |
15 | import java.io.File;
16 | import java.io.IOException;
17 | import java.util.Map;
18 |
19 |
20 |
21 | public class InfoMapExtractorTest {
22 |
23 | InfoMapExtractor infoMapExtractor = new InfoMapExtractor();
24 | String info;
25 | @Before
26 | public void init() throws IOException{
27 | info = FileUtils.readFileToString(new File("src/test/resources/info.txt"));
28 | }
29 |
30 | @Test
31 | public void sectionDataParseTest() throws IOException{
32 | Map sectionInfoMap = infoMapExtractor.extractInfoAsHashMap(info, "Clients");
33 | Assert.assertTrue(sectionInfoMap.get("connected_clients").equals("1"));
34 | Assert.assertTrue(sectionInfoMap.get("client_longest_output_list").equals("0"));
35 | Map sectionInfoMap2 = infoMapExtractor.extractInfoAsHashMap(info, "Memory");
36 | Assert.assertTrue(sectionInfoMap2.get("used_memory").equals("1031856"));
37 | Assert.assertTrue(sectionInfoMap2.get("used_memory_human").equals("1007.67K"));
38 | }
39 |
40 | @Test
41 | public void invalidSectionDataParseTest() throws IOException{
42 | Map sectionInfoMap3 = infoMapExtractor.extractInfoAsHashMap(info, "No");
43 | Assert.assertTrue(sectionInfoMap3.size() == 0);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/appdynamics/extensions/redis/utils/InfoMapExtractor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013. AppDynamics LLC and its affiliates.
3 | * * All Rights Reserved.
4 | * * This is unpublished proprietary source code of AppDynamics LLC and its affiliates.
5 | * * The copyright notice above does not evidence any actual or intended publication of such source code.
6 | */
7 |
8 | package com.appdynamics.extensions.redis.utils;
9 |
10 | import com.google.common.base.Splitter;
11 | import com.google.common.collect.Maps;
12 |
13 | import java.util.Map;
14 |
15 | public class InfoMapExtractor {
16 |
17 | public Map extractInfoAsHashMap(String info, String sectionName) {
18 | Map infoMap = Maps.newHashMap();
19 | Splitter sectionSplitter = Splitter.on('#')
20 | .omitEmptyStrings()
21 | .trimResults();
22 | for (String section : sectionSplitter.split(info)) {
23 | if (!section.toLowerCase().startsWith(sectionName.toLowerCase())) {
24 | continue;
25 | }
26 | return sectionMapGenerator(section, sectionName);
27 | }
28 | return infoMap;
29 | }
30 |
31 | private Map sectionMapGenerator(String sectionData, String sectionName) {
32 | Map infoMap = Maps.newHashMap();
33 | Splitter lineSplitter = Splitter.on(System.getProperty("line.separator"))
34 | .omitEmptyStrings()
35 | .trimResults();
36 | for (String line : lineSplitter.split(sectionData)) {
37 | if (line.toLowerCase().startsWith(sectionName)) {
38 | continue;
39 | }
40 | String[] infoLine = line.split(":");
41 | if (infoLine.length == 2 && positiveNumber(infoLine[1].trim())) {
42 | infoMap.put(infoLine[0].trim(), removeInvalidCharacters(infoLine[1].trim()));
43 | }
44 |
45 | }
46 | return infoMap;
47 | }
48 |
49 | private boolean positiveNumber(String trim) {
50 | return !trim.contains("-");
51 | }
52 |
53 | private String removeInvalidCharacters(String metric) {
54 | return metric.replaceAll("%", "")
55 | .replaceAll("count=", "");
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/resources/info.txt:
--------------------------------------------------------------------------------
1 | # Server
2 | redis_version:3.2.9
3 | redis_git_sha1:00000000
4 | redis_git_dirty:0
5 | redis_build_id:90399b885d95cf76
6 | redis_mode:standalone
7 | os:Darwin 16.6.0 x86_64
8 | arch_bits:64
9 | multiplexing_api:kqueue
10 | gcc_version:4.2.1
11 | process_id:71759
12 | run_id:9dd65f7e1620c48810cb740708c98a52d7202230
13 | tcp_port:6379
14 | uptime_in_seconds:69567
15 | uptime_in_days:0
16 | hz:10
17 | lru_clock:8707764
18 | executable:/usr/local/opt/redis-3.2.9/src/redis-server
19 | config_file:
20 |
21 | # Clients
22 | connected_clients:1
23 | client_longest_output_list:0
24 | client_biggest_input_buf:0
25 | blocked_clients:
26 |
27 | # Memory
28 | used_memory:1031856
29 | used_memory_human:1007.67K
30 | used_memory_rss:1527808
31 | used_memory_rss_human:1.46M
32 | used_memory_peak:1452880
33 | used_memory_peak_human:1.39M
34 | total_system_memory:17179869184
35 | total_system_memory_human:16.00G
36 | used_memory_lua:37888
37 | used_memory_lua_human:37.00K
38 | maxmemory:0
39 | maxmemory_human:0B
40 | maxmemory_policy:noeviction
41 | mem_fragmentation_ratio:1.48
42 | mem_allocator:libc
43 |
44 | # Persistence
45 | loading:0
46 | rdb_changes_since_last_save:0
47 | rdb_bgsave_in_progress:0
48 | rdb_last_save_time:1501810421
49 | rdb_last_bgsave_status:ok
50 | rdb_last_bgsave_time_sec:-1
51 | rdb_current_bgsave_time_sec:-1
52 | aof_enabled:0
53 | aof_rewrite_in_progress:0
54 | aof_rewrite_scheduled:0
55 | aof_last_rewrite_time_sec:-1
56 | aof_current_rewrite_time_sec:-1
57 | aof_last_bgrewrite_status:ok
58 | aof_last_write_status:ok
59 |
60 | # Stats
61 | total_connections_received:161
62 | total_commands_processed:446
63 | instantaneous_ops_per_sec:0
64 | total_net_input_bytes:12587
65 | total_net_output_bytes:6617622
66 | instantaneous_input_kbps:0.00
67 | instantaneous_output_kbps:0.00
68 | rejected_connections:0
69 | sync_full:0
70 | sync_partial_ok:0
71 | sync_partial_err:0
72 | expired_keys:0
73 | evicted_keys:0
74 | keyspace_hits:2
75 | keyspace_misses:2
76 | pubsub_channels:0
77 | pubsub_patterns:0
78 | latest_fork_usec:0
79 | migrate_cached_sockets:0
80 |
81 | # Replication
82 | role:master
83 | connected_slaves:0
84 | master_repl_offset:0
85 | repl_backlog_active:0
86 | repl_backlog_size:1048576
87 | repl_backlog_first_byte_offset:0
88 | repl_backlog_histlen:0
89 |
90 | # CPU
91 | used_cpu_sys:9.87
92 | used_cpu_user:4.91
93 | used_cpu_sys_children:0.00
94 | used_cpu_user_children:0.00
95 |
96 | # Cluster
97 | cluster_enabled:0
98 |
99 | # Keyspace
100 | db0:keys=41,expires=0,avg_ttl=0
--------------------------------------------------------------------------------
/src/main/java/com/appdynamics/extensions/redis/RedisMonitor.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2017 AppDynamics, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.appdynamics.extensions.redis;
17 |
18 | import com.appdynamics.extensions.ABaseMonitor;
19 | import com.appdynamics.extensions.TasksExecutionServiceProvider;
20 | import com.appdynamics.extensions.util.AssertUtils;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import java.util.List;
25 | import java.util.Map;
26 |
27 | import static com.appdynamics.extensions.redis.utils.Constants.DEFAULT_METRIC_PREFIX;
28 |
29 | public class RedisMonitor extends ABaseMonitor {
30 |
31 | private static final Logger logger = LoggerFactory.getLogger(RedisMonitor.class);
32 | private static long previousTimeStamp = System.currentTimeMillis();
33 | private static long currentTimeStamp = System.currentTimeMillis();
34 |
35 | @Override
36 | protected String getDefaultMetricPrefix() {
37 | return DEFAULT_METRIC_PREFIX;
38 | }
39 |
40 | @Override
41 | public String getMonitorName() {
42 | return "Redis Monitor";
43 | }
44 |
45 | @Override
46 | protected void doRun(TasksExecutionServiceProvider serviceProvider) {
47 | previousTimeStamp = currentTimeStamp;
48 | currentTimeStamp = System.currentTimeMillis();
49 | List