(self)
Retrieve length and entries from Redis' SLOWLOG

        This will parse through all entries of the SLOWLOG and select ones
        within the time range between the last seen entries and now
Retrieve length and entries from Redis' SLOWLOG
Retrieve length and entries from Redis SLOWLOG
def _check_slowlog(self):
        """Retrieve length and entries from Redis' SLOWLOG

        This will parse through all entries of the SLOWLOG and select ones
        within the time range between the last seen entries and now

        """
        conn = self._get_conn(self.instance)

        # Use fixed version of parse_slowlog_get callback for the
        # 'SLOWLOG GET' command; taken from upstream/master since it
        # will not be released in redis==3.5.3
        # - https://github.com/andymccurdy/redis-py/issues/1428#issuecomment-749692873
        # - upstream/master: https://github.com/andymccurdy/redis-py/commit/bc5854217b4e94eb7a33e3da5738858a17135ca5
        def upstream_parse_slowlog_get(response, **options):
            space = ' ' if options.get('decode_responses', False) else b' '
            return [
                {
                    'id': item[0],
                    'start_time': int(item[1]),
                    'duration': int(item[2]),
                    'command':
                    # Redis Enterprise injects another entry at index [3], which has
                    # the complexity info (i.e. the value N in case the command has
                    # an O(N) complexity) instead of the command.
                    space.join(item[3]) if isinstance(item[3], list) else space.join(item[4]),
                }
                for item in response
            ]

        conn.set_response_callback("SLOWLOG GET", upstream_parse_slowlog_get)

        if not self.instance.get(MAX_SLOW_ENTRIES_KEY):
            try:
                max_slow_entries = int(conn.config_get(MAX_SLOW_ENTRIES_KEY)[MAX_SLOW_ENTRIES_KEY])
                if max_slow_entries > DEFAULT_MAX_SLOW_ENTRIES:
                    self.log.debug(
                        "Redis {0} is higher than {1}. Defaulting to {1}. "  # noqa: G001
                        "If you need a higher value, please set {0} in your check config".format(
                            MAX_SLOW_ENTRIES_KEY, DEFAULT_MAX_SLOW_ENTRIES
                        )
                    )
                    max_slow_entries = DEFAULT_MAX_SLOW_ENTRIES
            # No config on AWS Elasticache
            except redis.ResponseError:
                self.log.debug("Unable to collect length of slow log: CONFIG GET disabled in some managed Redis.")
                max_slow_entries = DEFAULT_MAX_SLOW_ENTRIES
        else:
            max_slow_entries = int(self.instance.get(MAX_SLOW_ENTRIES_KEY))

        # Get all slowlog entries
        try:
            slowlogs = conn.slowlog_get(max_slow_entries)
        except TypeError as e:
            # This catch is needed in PY2 because there is a known issue that has only been fixed after redis
            # dropped python 2 support
            # issue: https://github.com/andymccurdy/redis-py/issues/1475
            # fix: https://github.com/andymccurdy/redis-py/pull/1352
            # TODO: remove once PY2 is no longer supported
            self.log.exception(e)
            self.log.error(
                'There was an error retrieving slowlog, these metrics will be skipped. This issue is fixed on Agent 7+.'
                ' You can find more information about upgrading to agent 7 in '
                'https://docs.datadoghq.com/agent/versions/upgrade_to_agent_v7/?tab=linux'
            )
            slowlogs = []

        # Find slowlog entries between last timestamp and now using start_time
        slowlogs = [s for s in slowlogs if s['start_time'] > self.last_timestamp_seen]

        max_ts = 0
        # Slowlog entry looks like:
        #  {'command': 'LPOP somekey',
        #   'duration': 11238,
        #   'id': 496L,
        #   'start_time': 1422529869}
        for slowlog in slowlogs:
            if slowlog['start_time'] > max_ts:
                max_ts = slowlog['start_time']

            slowlog_tags = list(self.tags)
            command = slowlog['command'].split()
            if len(command) > 0:
                slowlog_tags.append('command:{}'.format(ensure_unicode(command[0])))

            value = slowlog['duration']
            self.histogram('redis.slowlog.micros', value, tags=slowlog_tags)

        if max_ts != 0:
            self.last_timestamp_seen = max_ts
def _check_slowlog ( self ) : conn = self . _get_conn ( self . instance ) # Use fixed version of parse_slowlog_get callback for the # 'SLOWLOG GET' command; taken from upstream/master since it # will not be released in redis==3.5.3 # - https://github.com/andymccurdy/redis-py/issues/1428#issuecomment-749692873 # - upstream/master: https://github.com/andymccurdy/redis-py/commit/bc5854217b4e94eb7a33e3da5738858a17135ca5 def upstream_parse_slowlog_get ( response , * * options ) : space = ' ' if options . get ( 'decode_responses' , False ) else b' ' return [ { 'id' : item [ 0 ] , 'start_time' : int ( item [ 1 ] ) , 'duration' : int ( item [ 2 ] ) , 'command' : # Redis Enterprise injects another entry at index [3], which has # the complexity info (i.e. the value N in case the command has # an O(N) complexity) instead of the command. space . join ( item [ 3 ] ) if isinstance ( item [ 3 ] , list ) else space . join ( item [ 4 ] ) , } for item in response ] conn . set_response_callback ( "SLOWLOG GET" , upstream_parse_slowlog_get ) if not self . instance . get ( MAX_SLOW_ENTRIES_KEY ) : try : max_slow_entries = int ( conn . config_get ( MAX_SLOW_ENTRIES_KEY ) [ MAX_SLOW_ENTRIES_KEY ] ) if max_slow_entries > DEFAULT_MAX_SLOW_ENTRIES : self . log . debug ( "Redis {0} is higher than {1}. Defaulting to {1}. " # noqa: G001 "If you need a higher value, please set {0} in your check config" . format ( MAX_SLOW_ENTRIES_KEY , DEFAULT_MAX_SLOW_ENTRIES ) ) max_slow_entries = DEFAULT_MAX_SLOW_ENTRIES # No config on AWS Elasticache except redis . ResponseError : self . log . debug ( "Unable to collect length of slow log: CONFIG GET disabled in some managed Redis." ) max_slow_entries = DEFAULT_MAX_SLOW_ENTRIES else : max_slow_entries = int ( self . instance . get ( MAX_SLOW_ENTRIES_KEY ) ) # Get all slowlog entries try : slowlogs = conn . slowlog_get ( max_slow_entries ) except TypeError as e : # This catch is needed in PY2 because there is a known issue that has only been fixed after redis # dropped python 2 support # issue: https://github.com/andymccurdy/redis-py/issues/1475 # fix: https://github.com/andymccurdy/redis-py/pull/1352 # TODO: remove once PY2 is no longer supported self . log . exception ( e ) self . log . error ( 'There was an error retrieving slowlog, these metrics will be skipped. This issue is fixed on Agent 7+.' ' You can find more information about upgrading to agent 7 in ' 'https://docs.datadoghq.com/agent/versions/upgrade_to_agent_v7/?tab=linux' ) slowlogs = [ ] # Find slowlog entries between last timestamp and now using start_time slowlogs = [ s for s in slowlogs if s [ 'start_time' ] > self . last_timestamp_seen ] max_ts = 0 # Slowlog entry looks like: #  {'command': 'LPOP somekey', #   'duration': 11238, #   'id': 496L, #   'start_time': 1422529869} for slowlog in slowlogs : if slowlog [ 'start_time' ] > max_ts : max_ts = slowlog [ 'start_time' ] slowlog_tags = list ( self . tags ) command = slowlog [ 'command' ] . split ( ) if len ( command ) > 0 : slowlog_tags . append ( 'command:{}' . format ( ensure_unicode ( command [ 0 ] ) ) ) value = slowlog [ 'duration' ] self . histogram ( 'redis.slowlog.micros' , value , tags = slowlog_tags ) if max_ts != 0 : self . last_timestamp_seen = max_ts