Merge branch 'main' into fix/sync
This commit is contained in:
@@ -8,3 +8,8 @@ RQ_DASHBOARD_REDIS_URL=redis://redis:6379/0
|
|||||||
POSTGRES_DB=aperisolve
|
POSTGRES_DB=aperisolve
|
||||||
POSTGRES_USER=aperiuser
|
POSTGRES_USER=aperiuser
|
||||||
POSTGRES_PASSWORD=aperipass
|
POSTGRES_PASSWORD=aperipass
|
||||||
|
SENTRY_DSN=https://your-dsn@sentry.io/project-id
|
||||||
|
SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||||
|
SENTRY_PROFILES_SAMPLE_RATE=0.1
|
||||||
|
SENTRY_RELEASE=1.0.0
|
||||||
|
ENVIRONMENT=production
|
||||||
@@ -8,6 +8,12 @@ from datetime import datetime, timezone
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.flask import FlaskIntegration
|
||||||
|
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||||
|
from sentry_sdk.integrations.rq import RqIntegration
|
||||||
|
from sentry_sdk.integrations.threading import ThreadingIntegration
|
||||||
|
|
||||||
from flask import Flask, Response, abort, jsonify, render_template, request, send_file
|
from flask import Flask, Response, abort, jsonify, render_template, request, send_file
|
||||||
from redis import Redis
|
from redis import Redis
|
||||||
from rq import Queue
|
from rq import Queue
|
||||||
@@ -16,6 +22,33 @@ from .cleanup import cleanup_old_entries
|
|||||||
from .config import IMAGE_EXTENSIONS, RESULT_FOLDER, WORKER_FILES
|
from .config import IMAGE_EXTENSIONS, RESULT_FOLDER, WORKER_FILES
|
||||||
from .models import Image, Submission, db, init_db
|
from .models import Image, Submission, db, init_db
|
||||||
|
|
||||||
|
SENTRY_DSN = os.environ.get("SENTRY_DSN")
|
||||||
|
ENVIRONMENT = os.environ.get("ENVIRONMENT", "development")
|
||||||
|
|
||||||
|
if SENTRY_DSN:
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=SENTRY_DSN,
|
||||||
|
integrations=[
|
||||||
|
FlaskIntegration(),
|
||||||
|
SqlalchemyIntegration(),
|
||||||
|
RqIntegration(),
|
||||||
|
ThreadingIntegration(propagate_hub=True),
|
||||||
|
],
|
||||||
|
# Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||||
|
# Adjust this value in production (e.g., 0.1 for 10%)
|
||||||
|
traces_sample_rate=float(os.environ.get("SENTRY_TRACES_SAMPLE_RATE", "0.1")),
|
||||||
|
# Set profiles_sample_rate to 1.0 to profile 100% of sampled transactions.
|
||||||
|
profiles_sample_rate=float(os.environ.get("SENTRY_PROFILES_SAMPLE_RATE", "0.1")),
|
||||||
|
# Environment tag (production, staging, development)
|
||||||
|
environment=ENVIRONMENT,
|
||||||
|
# Release version (use git commit hash or version number)
|
||||||
|
release=os.environ.get("SENTRY_RELEASE", "1.0.0"),
|
||||||
|
# Send default PII (user IPs, etc.) - set to False for privacy
|
||||||
|
send_default_pii=False,
|
||||||
|
# Enable automatic breadcrumb tracking
|
||||||
|
enable_tracing=True,
|
||||||
|
)
|
||||||
|
|
||||||
app: Flask = Flask(__name__)
|
app: Flask = Flask(__name__)
|
||||||
app.json.sort_keys = False # type: ignore
|
app.json.sort_keys = False # type: ignore
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
|
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
|
||||||
@@ -35,6 +68,11 @@ queue = Queue(connection=redis_conn)
|
|||||||
@app.errorhandler(413)
|
@app.errorhandler(413)
|
||||||
def too_large(_: Any) -> tuple[Response, int]:
|
def too_large(_: Any) -> tuple[Response, int]:
|
||||||
"""Error Handler for Max File Size."""
|
"""Error Handler for Max File Size."""
|
||||||
|
sentry_sdk.set_context("upload", {
|
||||||
|
"content_length": request.content_length,
|
||||||
|
"max_allowed": app.config["MAX_CONTENT_LENGTH"],
|
||||||
|
})
|
||||||
|
sentry_sdk.capture_message("Upload failed: 413 Payload Too Large", level="warning")
|
||||||
return jsonify({"error": "Image size exceeded"}), 413
|
return jsonify({"error": "Image size exceeded"}), 413
|
||||||
|
|
||||||
|
|
||||||
@@ -43,6 +81,7 @@ def not_found(_: Any) -> str:
|
|||||||
"""Error Handler for 404 not found."""
|
"""Error Handler for 404 not found."""
|
||||||
return render_template("error.html", message="Resource not found", statuscode=404)
|
return render_template("error.html", message="Resource not found", statuscode=404)
|
||||||
|
|
||||||
|
# Sentry automatically captures 500 errors
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index() -> str:
|
def index() -> str:
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ psycopg2-binary
|
|||||||
types-Flask-SQLAlchemy
|
types-Flask-SQLAlchemy
|
||||||
sqlalchemy-stubs
|
sqlalchemy-stubs
|
||||||
Pillow
|
Pillow
|
||||||
gunicorn
|
gunicorn
|
||||||
|
sentry-sdk[flask,sqlalchemy,rq]
|
||||||
+33
-3
@@ -1,9 +1,31 @@
|
|||||||
"""Asynchronous worker for analyzing image submissions."""
|
"""Asynchronous worker for analyzing image submissions."""
|
||||||
|
|
||||||
|
import os
|
||||||
import threading
|
import threading
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import sentry_sdk
|
||||||
|
from sentry_sdk.integrations.rq import RqIntegration
|
||||||
|
from sentry_sdk.integrations.threading import ThreadingIntegration
|
||||||
|
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||||
|
|
||||||
|
# Initialize Sentry for workers (separate process from Flask app)
|
||||||
|
SENTRY_DSN = os.environ.get("SENTRY_DSN")
|
||||||
|
if SENTRY_DSN:
|
||||||
|
sentry_sdk.init(
|
||||||
|
dsn=SENTRY_DSN,
|
||||||
|
integrations=[
|
||||||
|
RqIntegration(),
|
||||||
|
ThreadingIntegration(propagate_hub=True), # Capture exceptions in threads
|
||||||
|
SqlalchemyIntegration(),
|
||||||
|
],
|
||||||
|
traces_sample_rate=float(os.environ.get("SENTRY_TRACES_SAMPLE_RATE", "0.1")),
|
||||||
|
environment=os.environ.get("ENVIRONMENT", "development"),
|
||||||
|
release=os.environ.get("SENTRY_RELEASE", "1.0.0"),
|
||||||
|
send_default_pii=False,
|
||||||
|
)
|
||||||
|
|
||||||
from .analyzers.binwalk import analyze_binwalk
|
from .analyzers.binwalk import analyze_binwalk
|
||||||
from .analyzers.decomposer import analyze_decomposer
|
from .analyzers.decomposer import analyze_decomposer
|
||||||
from .analyzers.exiftool import analyze_exiftool
|
from .analyzers.exiftool import analyze_exiftool
|
||||||
@@ -51,6 +73,10 @@ def analyze_image(submission_hash: str) -> None:
|
|||||||
image = Image.query.get_or_404(submission.image_hash) # type: ignore
|
image = Image.query.get_or_404(submission.image_hash) # type: ignore
|
||||||
|
|
||||||
if not submission or not image: # No submission found
|
if not submission or not image: # No submission found
|
||||||
|
sentry_sdk.capture_message(
|
||||||
|
f"Submission or image not found: {submission_hash}",
|
||||||
|
level="warning"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
submission.status = "running" # type: ignore
|
submission.status = "running" # type: ignore
|
||||||
@@ -70,6 +96,7 @@ def analyze_image(submission_hash: str) -> None:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
print(f"Error in {analyzer_func.__name__}: {e}")
|
print(f"Error in {analyzer_func.__name__}: {e}")
|
||||||
|
sentry_sdk.capture_exception(e)
|
||||||
|
|
||||||
analyzers = [
|
analyzers = [
|
||||||
(analyze_binwalk, img_path, result_path),
|
(analyze_binwalk, img_path, result_path),
|
||||||
@@ -100,8 +127,11 @@ def analyze_image(submission_hash: str) -> None:
|
|||||||
for thread in threads:
|
for thread in threads:
|
||||||
thread.join()
|
thread.join()
|
||||||
|
|
||||||
submission.status = "completed" # type: ignore
|
submission.status = "completed"
|
||||||
except Exception:
|
except Exception as e:
|
||||||
submission.status = "error" # type: ignore
|
sentry_sdk.capture_exception(e)
|
||||||
|
submission.status = "error"
|
||||||
finally:
|
finally:
|
||||||
db.session.commit() # pylint: disable=no-member
|
db.session.commit() # pylint: disable=no-member
|
||||||
|
# Flush Sentry events - wait up to 5 seconds for events to be sent
|
||||||
|
sentry_sdk.flush(timeout=5)
|
||||||
|
|||||||
Reference in New Issue
Block a user