Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Allow logging to disk #237

Merged
merged 5 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ x-common-variables: &kai-variables
DEMO_MODE: "False"
HUB_URL: ${HUB_URL:-https://tackle-konveyor-tackle.apps.example.com/hub}
IMPORTER_ARGS:
LOGLEVEL: info
LOG_LEVEL: info
LOG_DIR: "/podman_compose/logs"
NUM_WORKERS: 8
USE_HUB_IMPORTER: ${USE_HUB_IMPORTER:-False}

Expand All @@ -27,7 +28,7 @@ services:
OPENAI_API_KEY:
image: ${IMAGE:-quay.io/konveyor/kai}:${TAG:-stable}
volumes:
- ${PWD}:/podman_compose:ro,z
- ${PWD}:/podman_compose:rw,z
ports:
- "8080:8080"
depends_on:
Expand All @@ -39,7 +40,7 @@ services:
MODE: importer
image: ${IMAGE:-quay.io/konveyor/kai}:${TAG:-stable}
volumes:
- ${PWD}:/podman_compose:ro,z
- ${PWD}:/podman_compose:rw,z
depends_on:
- kai_db
profiles:
Expand Down
13 changes: 10 additions & 3 deletions example/run_demo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import json
import logging
import os
import sys
import time
Expand All @@ -12,8 +13,10 @@

# Ensure that we have 'kai' in our import path
sys.path.append("../../kai")
from kai import Report
from kai.kai_logging import KAI_LOG
from kai.kai_logging import formatter
from kai.report import Report

KAI_LOG = logging.getLogger(__name__)

SERVER_URL = "http://0.0.0.0:8080"
APP_NAME = "coolstore"
Expand Down Expand Up @@ -249,7 +252,11 @@ def run_demo(report):


if __name__ == "__main__":
KAI_LOG.setLevel("info".upper())
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
KAI_LOG.addHandler(console_handler)
KAI_LOG.setLevel("DEBUG")

start = time.time()
coolstore_analysis_dir = "./analysis/coolstore/output.yaml"
r = Report.load_report_from_file(coolstore_analysis_dir)
Expand Down
119 changes: 0 additions & 119 deletions kai/__init__.py
Original file line number Diff line number Diff line change
@@ -1,120 +1 @@
__version__ = "0.0.1"

from typing import Annotated, List

import typer

from kai.report import Report
from kai.result import LLMResult
from kai.service.incident_store.incident_store import IncidentStore

# from typing_extensions import Annotated


app = typer.Typer()

# report_app = typer.Typer()
# result_app = typer.Typer()

# app.add_typer(report_app, name="report", help="Generate a markdown report from a raw analysis yaml.")
# app.add_typer(result_app, name="result", help="Generate patches for given violations and incidents from an analysis yaml")


@app.command()
def report(analysis_path: str, output_dir: str):
"""
Generate a Markdown report of a given analysis
YAML to be read by a human
"""
report = Report.load_report_from_file(analysis_path)
r = dict(report)
print(f"We have results from {len(r.keys())} RuleSet(s) in {analysis_path}\n")
report.write_markdown(output_dir)


@app.command()
def generate(
path_to_report: str,
path_to_source: str,
example_initial_branch: str,
example_solved_branch: str,
path_to_output: str,
limit_rulesets: Annotated[List[str], typer.Option("--ruleset", "-r")] = None,
limit_violations: Annotated[List[str], typer.Option("--violation", "-v")] = None,
model: Annotated[str, typer.Option("--model", "-m")] = "gpt-3.5-turbo-16k",
):
# model: Annotated[Optional[str], typer.Argument()] = "gpt-3.5-turbo-16k"):
"""
Generate patches for given violations and incidents from an analysis yaml report

- path_to_report: Path to the analysis yaml report

- path_to_source: Path to the source code to be patched

- example_initial_branch: Branch name for the initial state of the source code

- example_solved_branch: Branch name for the solved state of the source code

- path_to_output: Path to the output directory for the patches

- limit_rulesets: Limit to specific rulesets (defaults to 'None', meaning to run all)

- limit_violations: Limit to specific violations (defaults to 'None', meaning to run all)

- model: Model name to use for generating the patches (defaults to 'gpt-3.5-turbo-16k', 'gpt-4-1106-preview' is another good option)
"""
print(
f"Generating patches for {path_to_report} for example app at {path_to_source}"
)
print(f"Initial branch: {example_initial_branch}")
print(f"Solved branch: {example_solved_branch}")
print(f"Output directory: {path_to_output}")
print(f"Model: {model}")
print(f"Limit to ruleset(s): {limit_rulesets}")
print(f"Limit to violation(s): {limit_violations}")

llmResult = LLMResult(path_to_source, example_initial_branch, example_solved_branch)
llmResult.parse_report(path_to_report)
llmResult.process(path_to_output, model, limit_rulesets, limit_violations)
print(f"Completed processing, output written to {path_to_output}\n")


@app.command()
def load(report_path: str, output_dir: str):
"""
Load the incident store with the given applications
write the cached_violations to a file for later use
"""
incident_store = IncidentStore(report_path, output_dir)
incident_store.load_incident_store()


@app.command()
def patch(ruleset: str, violation: str, report_path: str, output_dir: str):
"""
Generate patches for a specific violation
"""
print(f"Generating patches for {ruleset} - {violation}")
incident_store = IncidentStore(report_path, output_dir)
patches = incident_store.get_solved_issue(ruleset, violation)
if len(patches) == 0:
print(f"No patches found for {ruleset} - {violation}")
else:
for patch in patches:
print(f"Patch: {patch}")
return patches


@app.command()
def common(ruleset: str, violation: str, report_path: str, output_dir: str):
"""
Find common violations for a specific violation
"""
print(f"Finding common violations for {ruleset} - {violation}")
incident_store = IncidentStore(report_path, output_dir)
violations = incident_store.find_common_violations(ruleset, violation)
if violations is None:
print(f"No common violations found for {ruleset} - {violation}")
for violation in violations:
print(f"Violation: {violation}")
return violations
2 changes: 2 additions & 0 deletions kai/config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
log_level = "info"
file_log_level = "debug"
log_dir = "$pwd/logs"
demo_mode = false
trace_enabled = true

Expand Down
3 changes: 2 additions & 1 deletion kai/embedding_provider.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import random
from abc import ABC, abstractmethod
from enum import Enum
Expand All @@ -9,7 +10,7 @@
from psycopg2 import sql
from psycopg2.extensions import connection

from kai.kai_logging import KAI_LOG
KAI_LOG = logging.getLogger(__name__)


class TrimStrategy(Enum):
Expand Down
4 changes: 3 additions & 1 deletion kai/hub_importer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import argparse
import logging
import os
import pprint
import tempfile
Expand All @@ -13,11 +14,12 @@
from git import GitCommandError, Repo
from pydantic import BaseModel, Field

from kai.kai_logging import KAI_LOG
from kai.models.kai_config import KaiConfig
from kai.report import Report
from kai.service.incident_store import Application, IncidentStore

KAI_LOG = logging.getLogger(__name__)


# BaseModel that also acts as a dict
class KaiBaseModel(BaseModel):
Expand Down
63 changes: 58 additions & 5 deletions kai/kai_logging.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,63 @@
import logging
import os

KAI_LOG = logging.getLogger(__name__)
console_handler = logging.StreamHandler()
from kai.models.kai_config import KaiConfig

parent_log = logging.getLogger("kai")

# console_handler = logging.StreamHandler()
# formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
formatter = logging.Formatter(
"%(levelname)s - %(asctime)s - [%(filename)20s:%(lineno)-4s - %(funcName)20s()] - %(message)s"
"%(levelname)s - %(asctime)s - %(name)s - [%(filename)20s:%(lineno)-4s - %(funcName)20s()] - %(message)s"
)
console_handler.setFormatter(formatter)
KAI_LOG.addHandler(console_handler)


def process_log_dir_replacements(log_dir: str):
##
# We want to replace $pwd with the location of the Kai project directory,
# this is needed to help with specifying from configuration
##
if log_dir.startswith("$pwd"):
log_dir = log_dir.replace(
"$pwd", os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
)
return log_dir


def setup_console_handler(logger, log_level: str = "INFO"):
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
print(f"Console logging for '{parent_log.name}' is set to level '{log_level}'")


def setup_file_handler(
logger, log_file_name: str, log_dir: str, log_level: str = "DEBUG"
):
# Ensure any needed log directories exist
log_dir = process_log_dir_replacements(log_dir)
log_file_path = os.path.join(log_dir, log_file_name)
if log_dir.startswith("$pwd"):
log_dir = os.path.join(os.getcwd(), log_dir[5:])
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)

file_handler = logging.FileHandler(log_file_path)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
print(
f"File logging for '{logger.name}' is set to level '{log_level}' writing to file: '{log_file_path}'"
)


def initLogging(console_log_level, file_log_level, log_dir, log_file="kai_server.log"):
setup_console_handler(parent_log, console_log_level)
setup_file_handler(parent_log, log_file, log_dir, file_log_level)
# Attempt to set the parent log level to
# most persmissive and allow child loggers to control what is filtered or not
parent_log.setLevel("DEBUG")


def initLoggingFromConfig(config: KaiConfig):
initLogging(config.log_level.upper(), config.file_log_level.upper(), config.log_dir)
4 changes: 3 additions & 1 deletion kai/llm_io_handler.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import itertools
import logging
import os
import time
import traceback
Expand All @@ -16,7 +17,6 @@
)

from kai.constants import PATH_TEMPLATES
from kai.kai_logging import KAI_LOG
from kai.model_provider import ModelProvider
from kai.models.file_solution import guess_language, parse_file_solution_content
from kai.service.incident_store.incident_store import IncidentStore
Expand All @@ -25,6 +25,8 @@
LLM_RETRIES = 5
LLM_RETRY_DELAY = 10

KAI_LOG = logging.getLogger(__name__)


def get_prompt(
model_provider: ModelProvider,
Expand Down
3 changes: 2 additions & 1 deletion kai/models/file_solution.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import logging
import re

from pydantic import BaseModel
from pygments import lexers
from pygments.util import ClassNotFound

from kai.kai_logging import KAI_LOG
KAI_LOG = logging.getLogger(__name__)


class FileSolutionContent(BaseModel):
Expand Down
4 changes: 4 additions & 0 deletions kai/models/kai_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ class KaiConfigModels(BaseModel):

class KaiConfig(BaseModel):
log_level: str = "info"
file_log_level: str = "info"
log_dir: str = os.path.join(
os.path.dirname(os.path.realpath(__file__)), "../../logs"
)
demo_mode: bool = False
trace_enabled: bool = False

Expand Down
3 changes: 2 additions & 1 deletion kai/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import hashlib
import json
import logging
import os
import shutil
from io import StringIO

import yaml

from kai.kai_logging import KAI_LOG
KAI_LOG = logging.getLogger(__name__)


class Report:
Expand Down
4 changes: 3 additions & 1 deletion kai/result.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
__all__ = ["LLMResult"]

import logging
import os

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_community.chat_models import ChatOpenAI

from kai.constants import PATH_TEMPLATES
from kai.kai_logging import KAI_LOG

from .report import Report
from .scm import GitDiff

KAI_LOG = logging.getLogger(__name__)


class LLMResult:
"""The intent of this class is to help us form several Prompt examples using a single application
Expand Down
3 changes: 2 additions & 1 deletion kai/scm.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
__all__ = ["GitDiff"]

import logging

from git import BadName, Repo

from kai.kai_logging import KAI_LOG
KAI_LOG = logging.getLogger(__name__)


class GitDiff:
Expand Down
Loading
Loading