logdetective 2.13.0__tar.gz → 3.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {logdetective-2.13.0 → logdetective-3.1.0}/PKG-INFO +54 -24
- {logdetective-2.13.0 → logdetective-3.1.0}/README.md +52 -21
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/constants.py +1 -1
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/logdetective.py +12 -24
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/models.py +1 -20
- logdetective-3.1.0/logdetective/prompts/message_template.j2 +2 -0
- logdetective-3.1.0/logdetective/prompts/snippet_message_template.j2 +2 -0
- logdetective-3.1.0/logdetective/prompts/snippet_system_prompt.j2 +38 -0
- logdetective-3.1.0/logdetective/prompts/staged_message_template.j2 +2 -0
- logdetective-3.1.0/logdetective/prompts/staged_system_prompt.j2 +45 -0
- logdetective-3.1.0/logdetective/prompts/system_prompt.j2 +57 -0
- logdetective-3.1.0/logdetective/prompts.py +87 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/prompts.yml +7 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/config.py +3 -2
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/models/metrics.py +7 -4
- logdetective-3.1.0/logdetective/server/metric.py +320 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/models.py +12 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/server.py +45 -75
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/utils.py +35 -26
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective.1.asciidoc +12 -7
- {logdetective-2.13.0 → logdetective-3.1.0}/pyproject.toml +8 -5
- logdetective-2.13.0/logdetective/server/metric.py +0 -127
- logdetective-2.13.0/logdetective/server/plot.py +0 -432
- {logdetective-2.13.0 → logdetective-3.1.0}/LICENSE +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/__init__.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/drain3.ini +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/extractors.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/prompts-summary-first.yml +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/prompts-summary-only.yml +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/remote_log.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/__init__.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/compressors.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/__init__.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/base.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/models/__init__.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/models/exceptions.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/models/koji.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/database/models/merge_request_jobs.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/emoji.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/exceptions.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/gitlab.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/koji.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/llm.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/templates/base_response.html.j2 +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/templates/gitlab_full_comment.md.j2 +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/templates/gitlab_short_comment.md.j2 +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/server/utils.py +0 -0
- {logdetective-2.13.0 → logdetective-3.1.0}/logdetective/skip_snippets.yml +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: logdetective
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 3.1.0
|
|
4
|
+
Summary: Analyze logs with a template miner and an LLM to discover errors and suggest solutions.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Author: Jiri Podivin
|
|
@@ -36,7 +36,6 @@ Requires-Dist: flexmock (>=0.12.2,<0.13.0) ; extra == "testing"
|
|
|
36
36
|
Requires-Dist: huggingface-hub (>=0.23.0,<1.4.0)
|
|
37
37
|
Requires-Dist: koji (>=1.35.0,<2.0.0) ; extra == "server" or extra == "server-testing"
|
|
38
38
|
Requires-Dist: llama-cpp-python (>0.2.56,!=0.2.86,<1.0.0)
|
|
39
|
-
Requires-Dist: matplotlib (>=3.8.4,<4.0.0) ; extra == "server" or extra == "server-testing"
|
|
40
39
|
Requires-Dist: numpy (>=1.26.0)
|
|
41
40
|
Requires-Dist: openai (>=1.82.1,<2.0.0) ; extra == "server" or extra == "server-testing"
|
|
42
41
|
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
@@ -97,12 +96,15 @@ Usage
|
|
|
97
96
|
|
|
98
97
|
To analyze a log file, run the script with the following command line arguments:
|
|
99
98
|
- `file` (required): The path or URL of the log file to be analyzed.
|
|
100
|
-
- `--model` (optional, default: "
|
|
101
|
-
- `--
|
|
102
|
-
- `--
|
|
103
|
-
- `--
|
|
104
|
-
- `--
|
|
105
|
-
- `--
|
|
99
|
+
- `--model` (optional, default: "granite-3.2-8b-instruct-GGUF"): The path or Hugging space name of the language model for analysis. For models from Hugging Face, write them as `namespace/repo_name`. As we are using LLama.cpp we want this to be in the `gguf` format. If the model is already on your machine it will skip the download.
|
|
100
|
+
- `--filename-suffix` (optional, default "Q4_K.gguf"): You can specify which suffix of the file to use. This option is applied when specifying model using the Hugging Face repository.
|
|
101
|
+
- `--n-clusters` (optional, default 8): Number of clusters for Drain to organize log chunks into. This only makes sense when you are summarizing with Drain.
|
|
102
|
+
- `--prompts PROMPTS` (Deprecated, replaced by `--prompts-config`) Path to prompt configuration file.
|
|
103
|
+
- `--prompts-config PROMPTS` Path to prompt configuration file.
|
|
104
|
+
- `--prompt-templates` Path to prompt template dir. Prompts must be valid Jinja templates, and system prompts must include field `system_time`.
|
|
105
|
+
- `--temperature` Temperature for inference.
|
|
106
|
+
- `--skip-snippets` Path to patterns for skipping snippets.
|
|
107
|
+
- `--csgrep` Use csgrep to process the log.
|
|
106
108
|
|
|
107
109
|
Example usage:
|
|
108
110
|
|
|
@@ -112,21 +114,27 @@ Or if the log file is stored locally:
|
|
|
112
114
|
|
|
113
115
|
logdetective ./data/logs.txt
|
|
114
116
|
|
|
115
|
-
Examples of using different models. Note the use of `--
|
|
117
|
+
Examples of using different models. Note the use of `--filename-suffix` (or `-F`) option, useful for models that were quantized:
|
|
116
118
|
|
|
117
|
-
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --
|
|
119
|
+
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --filename-suffix Q5_K_S.gguf
|
|
118
120
|
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --model 'fedora-copr/granite-3.2-8b-instruct-GGUF' -F Q4_K_M.gguf
|
|
119
121
|
|
|
120
122
|
Example of altered prompts:
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
cp -r ~/.local/lib/python3.13/site-packages/logdetective/prompts ~/my-prompts
|
|
125
|
+
vi ~/my-prompts/system_prompt.j2 # edit the system prompt there to better fit your needs
|
|
126
|
+
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --prompt-templates ~/my-prompts
|
|
127
|
+
|
|
128
|
+
Example of altered prompts (Deprecated):
|
|
129
|
+
|
|
130
|
+
cp ~/.local/lib/python3.13/site-packages/logdetective/prompts.yml ~/my-prompts.yml
|
|
131
|
+
vi ~/my-prompts.yml # edit the prompts there to better fit your needs
|
|
132
|
+
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --prompts ~/my-prompts.yml
|
|
125
133
|
|
|
126
134
|
|
|
127
135
|
Note that streaming with some models (notably Meta-Llama-3) is broken and can be worked around by `no-stream` option:
|
|
128
136
|
|
|
129
|
-
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --
|
|
137
|
+
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --filename-suffix Q5_K_M.gguf --no-stream
|
|
130
138
|
|
|
131
139
|
Choice of LLM
|
|
132
140
|
-------------
|
|
@@ -205,7 +213,8 @@ message is reported indicating that the 'check' phase of the rpm build process
|
|
|
205
213
|
failed with a bad exit status.
|
|
206
214
|
```
|
|
207
215
|
|
|
208
|
-
It looks like a wall of text. Similar to any log.
|
|
216
|
+
It looks like a wall of text. Similar to any log.
|
|
217
|
+
The main difference is that here we have the most significant lines of a logfile wrapped in `[ ] : ` and followed by textual explanation of the log text done by local LLM.
|
|
209
218
|
|
|
210
219
|
|
|
211
220
|
Contributing
|
|
@@ -373,14 +382,14 @@ Before doing `podman-compose up`, make sure to set `MODELS_PATH` environment var
|
|
|
373
382
|
```
|
|
374
383
|
$ export MODELS_PATH=/path/to/models/
|
|
375
384
|
$ ll $MODELS_PATH
|
|
376
|
-
-rw-r--r--. 1 tt tt 3.9G apr 10 17:18
|
|
385
|
+
-rw-r--r--. 1 tt tt 3.9G apr 10 17:18 granite-4.0-h-tiny-Q8_0.gguf
|
|
377
386
|
```
|
|
378
387
|
|
|
379
388
|
If the variable is not set, `./models` is mounted inside by default.
|
|
380
389
|
|
|
381
390
|
Model can be downloaded from [our Hugging Space](https://huggingface.co/fedora-copr) by:
|
|
382
391
|
```
|
|
383
|
-
$ curl -L -o models/
|
|
392
|
+
$ curl -L -o models/granite-3.2-8b-instruct-v0.3.Q4_K.gguf https://huggingface.co/fedora-copr/granite-3.2-8b-instruct-GGUF/resolve/main/ggml-model-Q4_K.gguf
|
|
384
393
|
```
|
|
385
394
|
|
|
386
395
|
Filtering snippet analysis by relevance
|
|
@@ -500,17 +509,38 @@ http GET "localhost:8080/metrics/analyze/requests?weeks=5" > /tmp/plot_weeks.svg
|
|
|
500
509
|
System Prompts
|
|
501
510
|
--------------
|
|
502
511
|
|
|
503
|
-
|
|
512
|
+
Prompts are defined as Jinja templates and placed in location specified by `--prompt-templates` option of the CLI utility, or `LOGDETECTIVE_PROMPT_TEMPLATES` environment variable of the container service. With further, optional, configuration in the `prompts.yml` configuration file.
|
|
513
|
+
|
|
514
|
+
All system prompt templates must include place for `system_time` variable.
|
|
515
|
+
|
|
516
|
+
If `references` list is defined in `prompts.yml`, templates must also include a handling for a list of references.
|
|
517
|
+
|
|
518
|
+
Example:
|
|
519
|
+
|
|
520
|
+
```jinja
|
|
521
|
+
{% if references %}
|
|
522
|
+
## References:
|
|
523
|
+
|
|
524
|
+
{% for reference in references %}
|
|
525
|
+
* {{ reference.name }} : {{ reference.link }}
|
|
526
|
+
{% endfor %}
|
|
527
|
+
{% endif %}
|
|
528
|
+
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
*Deprecated:*
|
|
532
|
+
|
|
533
|
+
*Prompt templates used by Log Detective are stored in the `prompts.yml` file.
|
|
504
534
|
It is possible to modify the file in place, or provide your own.
|
|
505
535
|
In CLI you can override prompt templates location using `--prompts` option,
|
|
506
536
|
while in the container service deployment the `LOGDETECTIVE_PROMPTS` environment variable
|
|
507
|
-
is used instead
|
|
537
|
+
is used instead.*
|
|
508
538
|
|
|
509
|
-
Prompts need to have a form compatible with python [format string syntax](https://docs.python.org/3/library/string.html#format-string-syntax)
|
|
510
|
-
with spaces, or replacement fields marked with curly braces, `{}` left for insertion of snippets
|
|
539
|
+
*Prompts need to have a form compatible with python [format string syntax](https://docs.python.org/3/library/string.html#format-string-syntax)
|
|
540
|
+
with spaces, or replacement fields marked with curly braces, `{}` left for insertion of snippets.*
|
|
511
541
|
|
|
512
|
-
Number of replacement fields in new prompts, must be the same as in originals.
|
|
513
|
-
Although their position may be different
|
|
542
|
+
*Number of replacement fields in new prompts, must be the same as in originals.
|
|
543
|
+
Although their position may be different.*
|
|
514
544
|
|
|
515
545
|
|
|
516
546
|
Skip Snippets
|
|
@@ -42,12 +42,15 @@ Usage
|
|
|
42
42
|
|
|
43
43
|
To analyze a log file, run the script with the following command line arguments:
|
|
44
44
|
- `file` (required): The path or URL of the log file to be analyzed.
|
|
45
|
-
- `--model` (optional, default: "
|
|
46
|
-
- `--
|
|
47
|
-
- `--
|
|
48
|
-
- `--
|
|
49
|
-
- `--
|
|
50
|
-
- `--
|
|
45
|
+
- `--model` (optional, default: "granite-3.2-8b-instruct-GGUF"): The path or Hugging space name of the language model for analysis. For models from Hugging Face, write them as `namespace/repo_name`. As we are using LLama.cpp we want this to be in the `gguf` format. If the model is already on your machine it will skip the download.
|
|
46
|
+
- `--filename-suffix` (optional, default "Q4_K.gguf"): You can specify which suffix of the file to use. This option is applied when specifying model using the Hugging Face repository.
|
|
47
|
+
- `--n-clusters` (optional, default 8): Number of clusters for Drain to organize log chunks into. This only makes sense when you are summarizing with Drain.
|
|
48
|
+
- `--prompts PROMPTS` (Deprecated, replaced by `--prompts-config`) Path to prompt configuration file.
|
|
49
|
+
- `--prompts-config PROMPTS` Path to prompt configuration file.
|
|
50
|
+
- `--prompt-templates` Path to prompt template dir. Prompts must be valid Jinja templates, and system prompts must include field `system_time`.
|
|
51
|
+
- `--temperature` Temperature for inference.
|
|
52
|
+
- `--skip-snippets` Path to patterns for skipping snippets.
|
|
53
|
+
- `--csgrep` Use csgrep to process the log.
|
|
51
54
|
|
|
52
55
|
Example usage:
|
|
53
56
|
|
|
@@ -57,21 +60,27 @@ Or if the log file is stored locally:
|
|
|
57
60
|
|
|
58
61
|
logdetective ./data/logs.txt
|
|
59
62
|
|
|
60
|
-
Examples of using different models. Note the use of `--
|
|
63
|
+
Examples of using different models. Note the use of `--filename-suffix` (or `-F`) option, useful for models that were quantized:
|
|
61
64
|
|
|
62
|
-
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --
|
|
65
|
+
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --filename-suffix Q5_K_S.gguf
|
|
63
66
|
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --model 'fedora-copr/granite-3.2-8b-instruct-GGUF' -F Q4_K_M.gguf
|
|
64
67
|
|
|
65
68
|
Example of altered prompts:
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
cp -r ~/.local/lib/python3.13/site-packages/logdetective/prompts ~/my-prompts
|
|
71
|
+
vi ~/my-prompts/system_prompt.j2 # edit the system prompt there to better fit your needs
|
|
72
|
+
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --prompt-templates ~/my-prompts
|
|
73
|
+
|
|
74
|
+
Example of altered prompts (Deprecated):
|
|
75
|
+
|
|
76
|
+
cp ~/.local/lib/python3.13/site-packages/logdetective/prompts.yml ~/my-prompts.yml
|
|
77
|
+
vi ~/my-prompts.yml # edit the prompts there to better fit your needs
|
|
78
|
+
logdetective https://kojipkgs.fedoraproject.org//work/tasks/3367/131313367/build.log --prompts ~/my-prompts.yml
|
|
70
79
|
|
|
71
80
|
|
|
72
81
|
Note that streaming with some models (notably Meta-Llama-3) is broken and can be worked around by `no-stream` option:
|
|
73
82
|
|
|
74
|
-
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --
|
|
83
|
+
logdetective https://example.com/logs.txt --model QuantFactory/Meta-Llama-3-8B-Instruct-GGUF --filename-suffix Q5_K_M.gguf --no-stream
|
|
75
84
|
|
|
76
85
|
Choice of LLM
|
|
77
86
|
-------------
|
|
@@ -150,7 +159,8 @@ message is reported indicating that the 'check' phase of the rpm build process
|
|
|
150
159
|
failed with a bad exit status.
|
|
151
160
|
```
|
|
152
161
|
|
|
153
|
-
It looks like a wall of text. Similar to any log.
|
|
162
|
+
It looks like a wall of text. Similar to any log.
|
|
163
|
+
The main difference is that here we have the most significant lines of a logfile wrapped in `[ ] : ` and followed by textual explanation of the log text done by local LLM.
|
|
154
164
|
|
|
155
165
|
|
|
156
166
|
Contributing
|
|
@@ -318,14 +328,14 @@ Before doing `podman-compose up`, make sure to set `MODELS_PATH` environment var
|
|
|
318
328
|
```
|
|
319
329
|
$ export MODELS_PATH=/path/to/models/
|
|
320
330
|
$ ll $MODELS_PATH
|
|
321
|
-
-rw-r--r--. 1 tt tt 3.9G apr 10 17:18
|
|
331
|
+
-rw-r--r--. 1 tt tt 3.9G apr 10 17:18 granite-4.0-h-tiny-Q8_0.gguf
|
|
322
332
|
```
|
|
323
333
|
|
|
324
334
|
If the variable is not set, `./models` is mounted inside by default.
|
|
325
335
|
|
|
326
336
|
Model can be downloaded from [our Hugging Space](https://huggingface.co/fedora-copr) by:
|
|
327
337
|
```
|
|
328
|
-
$ curl -L -o models/
|
|
338
|
+
$ curl -L -o models/granite-3.2-8b-instruct-v0.3.Q4_K.gguf https://huggingface.co/fedora-copr/granite-3.2-8b-instruct-GGUF/resolve/main/ggml-model-Q4_K.gguf
|
|
329
339
|
```
|
|
330
340
|
|
|
331
341
|
Filtering snippet analysis by relevance
|
|
@@ -445,17 +455,38 @@ http GET "localhost:8080/metrics/analyze/requests?weeks=5" > /tmp/plot_weeks.svg
|
|
|
445
455
|
System Prompts
|
|
446
456
|
--------------
|
|
447
457
|
|
|
448
|
-
|
|
458
|
+
Prompts are defined as Jinja templates and placed in location specified by `--prompt-templates` option of the CLI utility, or `LOGDETECTIVE_PROMPT_TEMPLATES` environment variable of the container service. With further, optional, configuration in the `prompts.yml` configuration file.
|
|
459
|
+
|
|
460
|
+
All system prompt templates must include place for `system_time` variable.
|
|
461
|
+
|
|
462
|
+
If `references` list is defined in `prompts.yml`, templates must also include a handling for a list of references.
|
|
463
|
+
|
|
464
|
+
Example:
|
|
465
|
+
|
|
466
|
+
```jinja
|
|
467
|
+
{% if references %}
|
|
468
|
+
## References:
|
|
469
|
+
|
|
470
|
+
{% for reference in references %}
|
|
471
|
+
* {{ reference.name }} : {{ reference.link }}
|
|
472
|
+
{% endfor %}
|
|
473
|
+
{% endif %}
|
|
474
|
+
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
*Deprecated:*
|
|
478
|
+
|
|
479
|
+
*Prompt templates used by Log Detective are stored in the `prompts.yml` file.
|
|
449
480
|
It is possible to modify the file in place, or provide your own.
|
|
450
481
|
In CLI you can override prompt templates location using `--prompts` option,
|
|
451
482
|
while in the container service deployment the `LOGDETECTIVE_PROMPTS` environment variable
|
|
452
|
-
is used instead
|
|
483
|
+
is used instead.*
|
|
453
484
|
|
|
454
|
-
Prompts need to have a form compatible with python [format string syntax](https://docs.python.org/3/library/string.html#format-string-syntax)
|
|
455
|
-
with spaces, or replacement fields marked with curly braces, `{}` left for insertion of snippets
|
|
485
|
+
*Prompts need to have a form compatible with python [format string syntax](https://docs.python.org/3/library/string.html#format-string-syntax)
|
|
486
|
+
with spaces, or replacement fields marked with curly braces, `{}` left for insertion of snippets.*
|
|
456
487
|
|
|
457
|
-
Number of replacement fields in new prompts, must be the same as in originals.
|
|
458
|
-
Although their position may be different
|
|
488
|
+
*Number of replacement fields in new prompts, must be the same as in originals.
|
|
489
|
+
Although their position may be different.*
|
|
459
490
|
|
|
460
491
|
|
|
461
492
|
Skip Snippets
|
|
@@ -4,7 +4,7 @@ in prompts.yaml instead.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
# pylint: disable=line-too-long
|
|
7
|
-
DEFAULT_ADVISOR = "fedora-copr/
|
|
7
|
+
DEFAULT_ADVISOR = "fedora-copr/granite-3.2-8b-instruct-GGUF"
|
|
8
8
|
|
|
9
9
|
PROMPT_TEMPLATE = """
|
|
10
10
|
Given following log snippets, and nothing else, explain what failure, if any, occured during build of this package.
|
|
@@ -41,31 +41,15 @@ def setup_args():
|
|
|
41
41
|
)
|
|
42
42
|
parser.add_argument(
|
|
43
43
|
"-F",
|
|
44
|
-
"--
|
|
44
|
+
"--filename-suffix",
|
|
45
45
|
help="Suffix of the model file name to be retrieved from Hugging Face.\
|
|
46
46
|
Makes sense only if the model is specified with Hugging Face name.",
|
|
47
47
|
default="Q4_K.gguf",
|
|
48
48
|
)
|
|
49
49
|
parser.add_argument("-n", "--no-stream", action="store_true")
|
|
50
|
-
parser.add_argument(
|
|
51
|
-
"-S",
|
|
52
|
-
"--summarizer",
|
|
53
|
-
type=str,
|
|
54
|
-
default="drain",
|
|
55
|
-
help="DISABLED: LLM summarization option was removed. \
|
|
56
|
-
Argument is kept for backward compatibility only.",
|
|
57
|
-
)
|
|
58
|
-
parser.add_argument(
|
|
59
|
-
"-N",
|
|
60
|
-
"--n_lines",
|
|
61
|
-
type=int,
|
|
62
|
-
default=None,
|
|
63
|
-
help="DISABLED: LLM summarization option was removed. \
|
|
64
|
-
Argument is kept for backward compatibility only.",
|
|
65
|
-
)
|
|
66
50
|
parser.add_argument(
|
|
67
51
|
"-C",
|
|
68
|
-
"--
|
|
52
|
+
"--n-clusters",
|
|
69
53
|
type=int,
|
|
70
54
|
default=8,
|
|
71
55
|
help="Number of clusters for Drain to organize log chunks into.\
|
|
@@ -75,10 +59,18 @@ def setup_args():
|
|
|
75
59
|
parser.add_argument("-q", "--quiet", action="store_true")
|
|
76
60
|
parser.add_argument(
|
|
77
61
|
"--prompts",
|
|
62
|
+
"--prompts-config",
|
|
78
63
|
type=str,
|
|
79
64
|
default=f"{os.path.dirname(__file__)}/prompts.yml",
|
|
80
65
|
help="Path to prompt configuration file.",
|
|
81
66
|
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--prompt-templates",
|
|
69
|
+
type=str,
|
|
70
|
+
default=f"{os.path.dirname(__file__)}/prompts",
|
|
71
|
+
help="Path to prompt template dir. Prompts must be valid Jinja templates, \
|
|
72
|
+
and system prompts must include field `system_time`.",
|
|
73
|
+
)
|
|
82
74
|
parser.add_argument(
|
|
83
75
|
"--temperature",
|
|
84
76
|
type=float,
|
|
@@ -86,7 +78,7 @@ def setup_args():
|
|
|
86
78
|
help="Temperature for inference.",
|
|
87
79
|
)
|
|
88
80
|
parser.add_argument(
|
|
89
|
-
"--
|
|
81
|
+
"--skip-snippets",
|
|
90
82
|
type=str,
|
|
91
83
|
default=f"{os.path.dirname(__file__)}/skip_snippets.yml",
|
|
92
84
|
help="Path to patterns for skipping snippets.",
|
|
@@ -105,10 +97,6 @@ async def run(): # pylint: disable=too-many-statements,too-many-locals,too-many
|
|
|
105
97
|
sys.stderr.write("Error: --quiet and --verbose is mutually exclusive.\n")
|
|
106
98
|
sys.exit(2)
|
|
107
99
|
|
|
108
|
-
# Emit warning about use of discontinued args
|
|
109
|
-
if args.n_lines or args.summarizer != "drain":
|
|
110
|
-
LOG.warning("LLM based summarization was removed. Drain will be used instead.")
|
|
111
|
-
|
|
112
100
|
# Logging facility setup
|
|
113
101
|
log_level = logging.INFO
|
|
114
102
|
if args.verbose >= 1:
|
|
@@ -117,7 +105,7 @@ async def run(): # pylint: disable=too-many-statements,too-many-locals,too-many
|
|
|
117
105
|
log_level = 0
|
|
118
106
|
|
|
119
107
|
# Get prompts configuration
|
|
120
|
-
prompts_configuration = load_prompts(args.prompts)
|
|
108
|
+
prompts_configuration = load_prompts(args.prompts, args.prompt_templates)
|
|
121
109
|
|
|
122
110
|
logging.basicConfig(stream=sys.stdout)
|
|
123
111
|
LOG.setLevel(log_level)
|
|
@@ -21,26 +21,7 @@ class PromptConfig(BaseModel):
|
|
|
21
21
|
snippet_system_prompt: str = DEFAULT_SYSTEM_PROMPT
|
|
22
22
|
staged_system_prompt: str = DEFAULT_SYSTEM_PROMPT
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
super().__init__()
|
|
26
|
-
if data is None:
|
|
27
|
-
return
|
|
28
|
-
self.prompt_template = data.get("prompt_template", PROMPT_TEMPLATE)
|
|
29
|
-
self.snippet_prompt_template = data.get(
|
|
30
|
-
"snippet_prompt_template", SNIPPET_PROMPT_TEMPLATE
|
|
31
|
-
)
|
|
32
|
-
self.prompt_template_staged = data.get(
|
|
33
|
-
"prompt_template_staged", PROMPT_TEMPLATE_STAGED
|
|
34
|
-
)
|
|
35
|
-
self.default_system_prompt = data.get(
|
|
36
|
-
"default_system_prompt", DEFAULT_SYSTEM_PROMPT
|
|
37
|
-
)
|
|
38
|
-
self.snippet_system_prompt = data.get(
|
|
39
|
-
"snippet_system_prompt", DEFAULT_SYSTEM_PROMPT
|
|
40
|
-
)
|
|
41
|
-
self.staged_system_prompt = data.get(
|
|
42
|
-
"staged_system_prompt", DEFAULT_SYSTEM_PROMPT
|
|
43
|
-
)
|
|
24
|
+
references: Optional[list[dict[str, str]]] = None
|
|
44
25
|
|
|
45
26
|
|
|
46
27
|
class SkipSnippets(BaseModel):
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
System time: {{ system_time }}
|
|
2
|
+
|
|
3
|
+
You are a highly capable expert system specialized in packaging and delivery of software using RPM,
|
|
4
|
+
within the RHEL ecosystem. Your purpose is to help package maintainers diagnose and resolve package build failures.
|
|
5
|
+
You are truthful, concise, and helpful.
|
|
6
|
+
|
|
7
|
+
## Input processing
|
|
8
|
+
|
|
9
|
+
You will work with snippets of logs produced during package build.
|
|
10
|
+
These snippets were extracted using data mining algorithm, and may not contain information
|
|
11
|
+
useful for diagnosing the root cause. Snippets without useful information must be disregarded.
|
|
12
|
+
|
|
13
|
+
## Analysis procedure
|
|
14
|
+
|
|
15
|
+
1. Provide the snippet with a short explanation.
|
|
16
|
+
2. If the snippet doesn't contain useful information, indicate the fact with a short sentence.
|
|
17
|
+
|
|
18
|
+
## Examples:
|
|
19
|
+
|
|
20
|
+
User: "Snippet: RPM build errors:"
|
|
21
|
+
Assistant: "Errors occurred during package build.
|
|
22
|
+
---
|
|
23
|
+
User: "Snippet: Copr build error: Build failed"
|
|
24
|
+
Assistant: "The build in Copr has failed."
|
|
25
|
+
---
|
|
26
|
+
User: "Snippet: /bin/tar: Removing leading `/' from member names"
|
|
27
|
+
Assistant: "This snippet is irrelevant."
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
{% if references %}
|
|
31
|
+
## References:
|
|
32
|
+
|
|
33
|
+
When necessary, suggest resources that may be helpful to user.
|
|
34
|
+
|
|
35
|
+
{% for reference in references %}
|
|
36
|
+
* {{ reference.name }} : {{ reference.link }}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endif %}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
System time: {{ system_time }}
|
|
2
|
+
|
|
3
|
+
You are a highly capable expert system specialized in packaging and delivery of software using RPM,
|
|
4
|
+
within the RHEL ecosystem. Your purpose is to help package maintainers diagnose and resolve package build failures.
|
|
5
|
+
You are truthful, concise, and helpful.
|
|
6
|
+
|
|
7
|
+
## Input processing
|
|
8
|
+
|
|
9
|
+
You will work with snippets of logs produced during package build.
|
|
10
|
+
These snippets were extracted using data mining algorithm, and may not contain information
|
|
11
|
+
useful for diagnosing the root cause. Snippets without useful information must be disregarded.
|
|
12
|
+
|
|
13
|
+
## Analysis procedure
|
|
14
|
+
|
|
15
|
+
Analyzed snippets are a format of [X] : [Y], where [X] is a log snippet, and [Y] is the explanation.
|
|
16
|
+
Do not reanalyze the raw log [X].
|
|
17
|
+
|
|
18
|
+
Snippets are delimited with '================'.
|
|
19
|
+
|
|
20
|
+
1. Analyze individual snippets, unless they already have analysis attached.
|
|
21
|
+
2. Disregard snippets that do not contain useful information.
|
|
22
|
+
3. Using information from all snippets provide explanation of the issue.
|
|
23
|
+
4. (Optional) Recommend a solution for the package maintainer, only if the cause is clear.
|
|
24
|
+
|
|
25
|
+
## Examples:
|
|
26
|
+
|
|
27
|
+
User: "
|
|
28
|
+
Snippets:
|
|
29
|
+
================
|
|
30
|
+
Snippet No. 1 at line #452:
|
|
31
|
+
[error: command 'gcc' failed: No such file or directory]: [`gcc` compiler is not available in the build environment]
|
|
32
|
+
================
|
|
33
|
+
Snippet No. 2 at line #452:
|
|
34
|
+
[Copr build error: Build failed]: [Package build in Copr failed]"
|
|
35
|
+
Assistant: "Package build in Copr failed due to missing `gcc` compiler. Ensure that all build requirements are correctly specified in the spec file."
|
|
36
|
+
|
|
37
|
+
{% if references %}
|
|
38
|
+
## References:
|
|
39
|
+
|
|
40
|
+
When necessary, suggest resources that may be helpful to user.
|
|
41
|
+
|
|
42
|
+
{% for reference in references %}
|
|
43
|
+
* {{ reference.name }} : {{ reference.link }}
|
|
44
|
+
{% endfor %}
|
|
45
|
+
{% endif %}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
System time: {{ system_time }}
|
|
2
|
+
|
|
3
|
+
You are a highly capable expert system specialized in packaging and delivery of software using RPM,
|
|
4
|
+
within the RHEL ecosystem. Your purpose is to help package maintainers diagnose and resolve package build failures.
|
|
5
|
+
You are truthful, concise, and helpful.
|
|
6
|
+
|
|
7
|
+
## Input processing
|
|
8
|
+
|
|
9
|
+
You will work with snippets of logs produced during a failed package build.
|
|
10
|
+
These snippets were extracted using data mining algorithm, and may not contain information
|
|
11
|
+
useful for diagnosing the root cause. Snippets without useful information must be disregarded.
|
|
12
|
+
General error messages, such as failure of commands used during build, are expected.
|
|
13
|
+
|
|
14
|
+
## Temporal Logic and Causality
|
|
15
|
+
|
|
16
|
+
Log snippets are typically provided in chronological order. When analyzing multiple snippets
|
|
17
|
+
the first significant error in the log is usually the root cause.
|
|
18
|
+
|
|
19
|
+
An error occurring at line #500 cannot be caused by an error occurring at line #1000.
|
|
20
|
+
|
|
21
|
+
Subsequent errors are often side effects of the initial failure. Focus your diagnosis on the primary trigger.
|
|
22
|
+
|
|
23
|
+
## Analysis procedure
|
|
24
|
+
|
|
25
|
+
Snippets are provided in order of appearance in the original log, with attached line number,
|
|
26
|
+
and are delimited with '================'.
|
|
27
|
+
Avoid generic or boilerplate recommendations (e.g., "check the logs," "ensure dependencies are met").
|
|
28
|
+
If a specific root cause is identified, the recommendation must directly address that cause.
|
|
29
|
+
|
|
30
|
+
1. Analyze individual snippets. Do not quote analyzed snippets.
|
|
31
|
+
2. Disregard snippets that do not contain useful information.
|
|
32
|
+
3. Using information from all snippets provide explanation of the issue. Be as specific as possible.
|
|
33
|
+
4. (Optional) Recommend a solution for the package maintainer, only if the cause is clear.
|
|
34
|
+
|
|
35
|
+
## Examples:
|
|
36
|
+
|
|
37
|
+
User: "
|
|
38
|
+
Snippets:
|
|
39
|
+
Snippet No. 1 at line #452:
|
|
40
|
+
|
|
41
|
+
error: command 'gcc' failed: No such file or directory
|
|
42
|
+
================
|
|
43
|
+
Snippet No. 2 at line #560:
|
|
44
|
+
|
|
45
|
+
Copr build error: Build failed
|
|
46
|
+
================"
|
|
47
|
+
Assistant: "Package build in Copr failed due to missing `gcc` compiler. Ensure that all build requirements are correctly specified in the spec file."
|
|
48
|
+
|
|
49
|
+
{% if references %}
|
|
50
|
+
## References:
|
|
51
|
+
|
|
52
|
+
When necessary, suggest resources that may be helpful to user.
|
|
53
|
+
|
|
54
|
+
{% for reference in references %}
|
|
55
|
+
* {{ reference.name }} : {{ reference.link }}
|
|
56
|
+
{% endfor %}
|
|
57
|
+
{% endif %}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from jinja2 import Environment, FileSystemLoader, Template
|
|
4
|
+
|
|
5
|
+
from logdetective.models import PromptConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PromptManager: # pylint: disable=too-many-instance-attributes
|
|
9
|
+
"""Manages prompts defined as jinja templates"""
|
|
10
|
+
_tmp_env: Environment
|
|
11
|
+
|
|
12
|
+
# Templates for system prompts
|
|
13
|
+
_default_system_prompt_template: Template
|
|
14
|
+
_snippet_system_prompt_template: Template
|
|
15
|
+
_staged_system_prompt_template: Template
|
|
16
|
+
|
|
17
|
+
# Templates for messages
|
|
18
|
+
default_message_template: Template
|
|
19
|
+
snippet_message_template: Template
|
|
20
|
+
staged_message_template: Template
|
|
21
|
+
|
|
22
|
+
_references: Optional[list[dict[str, str]]] = None
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self, prompts_path: str, prompts_configuration: Optional[PromptConfig] = None
|
|
26
|
+
) -> None:
|
|
27
|
+
self._tmp_env = Environment(loader=FileSystemLoader(prompts_path))
|
|
28
|
+
|
|
29
|
+
self._default_system_prompt_template = self._tmp_env.get_template(
|
|
30
|
+
"system_prompt.j2"
|
|
31
|
+
)
|
|
32
|
+
self._snippet_system_prompt_template = self._tmp_env.get_template(
|
|
33
|
+
"snippet_system_prompt.j2"
|
|
34
|
+
)
|
|
35
|
+
self._staged_system_prompt_template = self._tmp_env.get_template(
|
|
36
|
+
"staged_system_prompt.j2"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
self.default_message_template = self._tmp_env.get_template(
|
|
40
|
+
"message_template.j2"
|
|
41
|
+
)
|
|
42
|
+
self.snippet_message_template = self._tmp_env.get_template(
|
|
43
|
+
"snippet_message_template.j2"
|
|
44
|
+
)
|
|
45
|
+
self.staged_message_template = self._tmp_env.get_template(
|
|
46
|
+
"staged_message_template.j2"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if prompts_configuration:
|
|
50
|
+
self._references = prompts_configuration.references
|
|
51
|
+
|
|
52
|
+
# To maintain backward compatibility with `logdetective.models.PromptConfig`
|
|
53
|
+
@property
|
|
54
|
+
def default_system_prompt(self) -> str:
|
|
55
|
+
"""Render system prompt from a template"""
|
|
56
|
+
return self._default_system_prompt_template.render(
|
|
57
|
+
system_time=datetime.now(timezone.utc), references=self._references
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def snippet_system_prompt(self) -> str:
|
|
62
|
+
"""Render system prompt from a template"""
|
|
63
|
+
return self._snippet_system_prompt_template.render(
|
|
64
|
+
system_time=datetime.now(timezone.utc), references=self._references
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def staged_system_prompt(self) -> str:
|
|
69
|
+
"""Render system prompt from a template"""
|
|
70
|
+
return self._staged_system_prompt_template.render(
|
|
71
|
+
system_time=datetime.now(timezone.utc), references=self._references
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def prompt_template(self) -> str:
|
|
76
|
+
"""Render message prompt from the template"""
|
|
77
|
+
return self.default_message_template.render()
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def snippet_prompt_template(self) -> str:
|
|
81
|
+
"""Render message prompt from the template"""
|
|
82
|
+
return self.snippet_message_template.render()
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def prompt_template_staged(self) -> str:
|
|
86
|
+
"""Render message prompt from the template"""
|
|
87
|
+
return self.staged_message_template.render()
|
|
@@ -88,3 +88,10 @@ staged_system_prompt: |
|
|
|
88
88
|
You never speculate about package being built or fabricate information.
|
|
89
89
|
If you do not know the answer, you acknowledge the fact and end your response.
|
|
90
90
|
Your responses must be as short as possible.
|
|
91
|
+
|
|
92
|
+
# Optional references, to be used when constructing prompt from Jinja template
|
|
93
|
+
# references:
|
|
94
|
+
# - name: Fedora Packaging Guidelines
|
|
95
|
+
# link: https://docs.fedoraproject.org/en-US/packaging-guidelines/
|
|
96
|
+
# - name: Mock user documentation
|
|
97
|
+
# link: https://rpm-software-management.github.io/mock/
|