<commit_before>"""
Status checks for LORE.

Notes:

* Useful messages are logged, but NO_CONFIG is returned whether
  settings are missing or invalid, to prevent information leakage.
* Different services provide different information, but all should return
  "up," DOWN, or NO_CONFIG for the "status" key.
"""

from datetime import datetime
import logging

from django.conf import settings
from django.http import JsonResponse, Http404
from elasticsearch import Elasticsearch, ConnectionError as ESConnectionError
from kombu.utils.url import _parse_url as parse_redis_url
from psycopg2 import connect, OperationalError
from redis import StrictRedis, ConnectionError as RedisConnectionError

log = logging.getLogger(__name__)

UP = "up"
DOWN = "down"
NO_CONFIG = "no config found"
HTTP_OK = 200
SERVICE_UNAVAILABLE = 503
TIMEOUT_SECONDS = 5


def get_pg_info():
    """Check PostgreSQL connection."""
    log.debug("entered get_pg_info")
    try:
        conf = settings.DATABASES['default']
        database = conf["NAME"]
        user = conf["USER"]
        host = conf["HOST"]
        port = conf["PORT"]
        password = conf["PASSWORD"]
    except (AttributeError, KeyError):
        log.error("No PostgreSQL connection info found in settings.")
        return {"status": NO_CONFIG}
    except TypeError:
        return {"status": DOWN}
    log.debug("got past getting conf")
    try:
        start = datetime.now()
        connection = connect(
            database=database, user=user, host=host,
            port=port, password=password, connect_timeout=TIMEOUT_SECONDS,
        )
        log.debug("at end of context manager")
        micro = (datetime.now() - start).microseconds
        connection.close()
    except (OperationalError, KeyError):
        log.error("Invalid PostgreSQL connection info in settings: %s", conf)
        return {"status": DOWN}
    log.debug("got to end of postgres check successfully")
    return {"status": UP, "response_microseconds": micro}


def get_redis_info():
    """Check Redis connection."""
    try:
        url = settings.BROKER_URL
        _, host, port, _, _, db, _ = parse_redis_url(url)
    except AttributeError:
        log.error("No valid Redis connection info found in settings.")
        return {"status": NO_CONFIG}

    start = datetime.now()
    try:
        rdb = StrictRedis(
            host=host, port=port, db=db, socket_timeout=TIMEOUT_SECONDS)
        info = rdb.info()
    except (RedisConnectionError, TypeError):
        return {"status": DOWN}
    micro = (datetime.now() - start).microseconds
    del rdb  # the redis package does not support Redis's QUIT.
    ret = {
        "status": UP, "response_microseconds": micro,
    }
    fields = ("uptime_in_seconds", "used_memory", "used_memory_peak")
    ret.update({x: info[x] for x in fields})
    return ret
<commit_msg>Added handling for Redis ResponseError.<commit_after>"""
Status checks for LORE.

Notes:

* Useful messages are logged, but NO_CONFIG is returned whether
  settings are missing or invalid, to prevent information leakage.
* Different services provide different information, but all should return
  "up," DOWN, or NO_CONFIG for the "status" key.
"""

from datetime import datetime
import logging

from django.conf import settings
from django.http import JsonResponse, Http404
from elasticsearch import Elasticsearch, ConnectionError as ESConnectionError
from kombu.utils.url import _parse_url as parse_redis_url
from psycopg2 import connect, OperationalError
from redis import (
    StrictRedis,
    ConnectionError as RedisConnectionError,
    ResponseError as RedisResponseError,
)

log = logging.getLogger(__name__)

UP = "up"
DOWN = "down"
NO_CONFIG = "no config found"
HTTP_OK = 200
SERVICE_UNAVAILABLE = 503
TIMEOUT_SECONDS = 5


def get_pg_info():
    """Check PostgreSQL connection."""
    log.debug("entered get_pg_info")
    try:
        conf = settings.DATABASES['default']
        database = conf["NAME"]
        user = conf["USER"]
        host = conf["HOST"]
        port = conf["PORT"]
        password = conf["PASSWORD"]
    except (AttributeError, KeyError):
        log.error("No PostgreSQL connection info found in settings.")
        return {"status": NO_CONFIG}
    except TypeError:
        return {"status": DOWN}
    log.debug("got past getting conf")
    try:
        start = datetime.now()
        connection = connect(
            database=database, user=user, host=host,
            port=port, password=password, connect_timeout=TIMEOUT_SECONDS,
        )
        log.debug("at end of context manager")
        micro = (datetime.now() - start).microseconds
        connection.close()
    except (OperationalError, KeyError):
        log.error("Invalid PostgreSQL connection info in settings: %s", conf)
        return {"status": DOWN}
    log.debug("got to end of postgres check successfully")
    return {"status": UP, "response_microseconds": micro}


def get_redis_info():
    """Check Redis connection."""
    try:
        url = settings.BROKER_URL
        _, host, port, _, _, db, _ = parse_redis_url(url)
    except AttributeError:
        log.error("No valid Redis connection info found in settings.")
        return {"status": NO_CONFIG}

    start = datetime.now()
    try:
        rdb = StrictRedis(
            host=host, port=port, db=db, socket_timeout=TIMEOUT_SECONDS)
        info = rdb.info()
    except (RedisConnectionError, TypeError) as ex:
        log.error("Error making Redis connection: %s", ex.args)
        return {"status": DOWN}
    except RedisResponseError as ex:
        log.error("Bad Redis response: %s", ex.args)
        return {"status": DOWN, "message": "auth error"}
    micro = (datetime.now() - start).microseconds
    del rdb  # the redis package does not support Redis's QUIT.
    ret = {
        "status": UP, "response_microseconds": micro,
    }
    fields = ("uptime_in_seconds", "used_memory", "used_memory_peak")
    ret.update({x: info[x] for x in fields})
    return ret

{'fraction_non_alphanumeric': 0.10291909924937448, 'fraction_numerical': 0.003669724770642202, 'mean_word_length': 3.222535211267606, 'pattern_counts': {'":': 20, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7271490', 'n_tokens_mistral': 1749, 'n_tokens_neox': 1705, 'n_words': 544}