Merge pull request #16 from Aignosi/SIENTIAPDE-1199-revisar-e-testar-observabilidade

Sientiapde 1199 revisar e testar observabilidade
This commit is contained in:
Matheus Demoner
2025-08-25 10:14:52 -03:00
committed by GitHub
11 changed files with 77 additions and 40 deletions

View File

@@ -5,7 +5,7 @@ asyncua
redis redis
aiokafka aiokafka
pymongo pymongo
git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.3.7 git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.4.1
git+ssh://git@github.com/Aignosi/sientia-mlops-library.git@0.38.5 git+ssh://git@github.com/Aignosi/sientia-mlops-library.git@0.38.5
pydruid[pandas] pydruid[pandas]
prometheus-client prometheus-client

View File

@@ -3,7 +3,7 @@ from temporalio import workflow
with workflow.unsafe.imports_passed_through(): with workflow.unsafe.imports_passed_through():
from sientia_do.temporal.activities.postgres import Postgres from sientia_do.temporal.activities.postgres import Postgres
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
from sientia_do.temporal.utils.logger import Logger from sientia_do.observability.logger import Logger
from scouter.activities.redis import Redis from scouter.activities.redis import Redis
from scouter.activities.gates import Gates from scouter.activities.gates import Gates
from scouter.activities.mongodb import MongoDB from scouter.activities.mongodb import MongoDB

View File

@@ -7,7 +7,7 @@ from temporalio import activity
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
from sientia_do.temporal.activities.base import BaseActivity from sientia_do.temporal.activities.base import BaseActivity
from sientia_do.temporal.utils.logger import Logger from sientia_do.observability.logger import Logger
class Faker(BaseActivity): class Faker(BaseActivity):

View File

@@ -6,7 +6,7 @@ with workflow.unsafe.imports_passed_through():
from sientia_do.notifications.models import NotificationLevel from sientia_do.notifications.models import NotificationLevel
from sientia_do.temporal.activities.base import BaseActivity from sientia_do.temporal.activities.base import BaseActivity
from sientia_do.notifications.handlers import NotificationHandler from sientia_do.notifications.handlers import NotificationHandler
from sientia_do.temporal.utils.logger import Logger from sientia_do.observability.logger import Logger
from scouter.utils.quality.filters import null_values_filter, out_of_bounds_filter from scouter.utils.quality.filters import null_values_filter, out_of_bounds_filter
from typing import Any from typing import Any
import traceback import traceback
@@ -89,8 +89,8 @@ class Gates(BaseActivity):
# Convert input data to DataFrame # Convert input data to DataFrame
df = DataFrame(input_data['data']) df = DataFrame(input_data['data'])
self.debug( self.info(
f"Aggregating time series data: {df.to_string()}", f"Aggregating time series data for {len(df)} rows",
metadata=metadata metadata=metadata
) )
@@ -147,10 +147,16 @@ class Gates(BaseActivity):
} }
result_df = DataFrame(list(result.values())) result_df = DataFrame(list(result.values()))
self.debug( self.info(
f"Aggregated data:\n {result_df.to_string()}", f"Aggregated data has {len(result_df)} rows",
metadata=metadata metadata=metadata
) )
self.debug(
f"Aggregated data: {result_df.to_string()}",
metadata=metadata
)
return result_df.to_dict() return result_df.to_dict()
except Exception as e: except Exception as e:
@@ -195,8 +201,8 @@ class Gates(BaseActivity):
data = DataFrame(input_data['data']) data = DataFrame(input_data['data'])
model_tags = input_data['model_tags'] model_tags = input_data['model_tags']
self.debug( self.info(
f"Applying quality gate to data: {data.to_string()}", f"Applying quality gate to data to {len(data)} rows",
metadata=metadata metadata=metadata
) )
@@ -249,8 +255,8 @@ class Gates(BaseActivity):
if policy == "DISCARD": if policy == "DISCARD":
data = data[~data.index.isin(filtered_data.index)] data = data[~data.index.isin(filtered_data.index)]
self.debug( self.info(
"Data quality gate applied", f"Data quality gate applied, final data has {len(data)} rows",
metadata=metadata metadata=metadata
) )
@@ -265,8 +271,18 @@ class Gates(BaseActivity):
""" """
metadata = input_data['metadata'] metadata = input_data['metadata']
self.info(
f"Writing metrics for {metadata['model_name']}",
metadata=metadata
)
metrics.LABORIOUS_DATA_WRITTEN_COUNT.labels( metrics.LABORIOUS_DATA_WRITTEN_COUNT.labels(
pod_id=self.pod_id, pod_id=self.pod_id,
model_name=metadata['model_name'], model_name=metadata['model_name'],
pipeline_name=metadata['workflow_name'] pipeline_name=metadata['workflow_name']
).inc() ).inc()
self.info(
f"Metrics written for {metadata['model_name']}",
metadata=metadata
)

View File

@@ -9,7 +9,7 @@ with workflow.unsafe.imports_passed_through():
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
from sientia_do.notifications.models import NotificationLevel from sientia_do.notifications.models import NotificationLevel
from sientia_do.temporal.activities.base import BaseActivity from sientia_do.temporal.activities.base import BaseActivity
from sientia_do.temporal.utils.logger import Logger from sientia_do.observability.logger import Logger
def clear_mongo_id(docs: list) -> list: def clear_mongo_id(docs: list) -> list:
@@ -87,7 +87,7 @@ class MongoDB(BaseActivity):
collection_name = input_data['collection_name'] collection_name = input_data['collection_name']
last_data_timestamp = input_data['last_data_timestamp'] last_data_timestamp = input_data['last_data_timestamp']
self.debug( self.info(
f"Loading data from MongoDB: {input_data}", f"Loading data from MongoDB: {input_data}",
metadata=metadata metadata=metadata
) )

View File

@@ -6,7 +6,7 @@ with workflow.unsafe.imports_passed_through():
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
from sientia_do.notifications.models import NotificationLevel from sientia_do.notifications.models import NotificationLevel
from sientia_do.temporal.activities.redis_base import Redis as RedisBase from sientia_do.temporal.activities.redis_base import Redis as RedisBase
from sientia_do.temporal.utils.logger import Logger from sientia_do.observability.logger import Logger
from typing import Any from typing import Any
from pandas import DataFrame from pandas import DataFrame
from datetime import datetime from datetime import datetime
@@ -29,6 +29,8 @@ class Redis(RedisBase):
metadata = input_data['metadata'] metadata = input_data['metadata']
key = f"last_data_timestamp_{input_data['workflow_name']}_{input_data['schedule_name']}" key = f"last_data_timestamp_{input_data['workflow_name']}_{input_data['schedule_name']}"
self.info(f"Getting last data timestamp for {key}")
try: try:
data_hold = self.get(key) data_hold = self.get(key)
except Exception as e: except Exception as e:
@@ -42,7 +44,7 @@ class Redis(RedisBase):
) )
raise e raise e
self.debug( self.info(
f"Last collected timestamp: {data_hold}", f"Last collected timestamp: {data_hold}",
metadata=metadata metadata=metadata
) )
@@ -60,6 +62,8 @@ class Redis(RedisBase):
metadata = input_data['metadata'] metadata = input_data['metadata']
key = f"last_data_timestamp_{input_data['workflow_name']}_{input_data['schedule_name']}" key = f"last_data_timestamp_{input_data['workflow_name']}_{input_data['schedule_name']}"
self.info(f"Putting last data timestamp for {key}")
data = DataFrame(input_data['data']) data = DataFrame(input_data['data'])
if data.empty: if data.empty:
@@ -70,7 +74,7 @@ class Redis(RedisBase):
last_data_timestamp = data['inserted_at'].max() last_data_timestamp = data['inserted_at'].max()
self.debug( self.info(
f"Last collected timestamp to insert: {last_data_timestamp}", f"Last collected timestamp to insert: {last_data_timestamp}",
metadata=metadata metadata=metadata
) )
@@ -116,6 +120,8 @@ class Redis(RedisBase):
key = f"held_data_{input_data['workflow_name']}_{input_data['schedule_name']}" key = f"held_data_{input_data['workflow_name']}_{input_data['schedule_name']}"
self.info(f"Getting held data for {key}")
try: try:
data_hold = self.get(key) data_hold = self.get(key)
except Exception as e: except Exception as e:
@@ -137,6 +143,8 @@ class Redis(RedisBase):
) )
return data_hold return data_hold
self.info(f"Grouping and holding data for {len(data)} rows")
try: try:
# Remove possibly removed tags # Remove possibly removed tags
@@ -195,8 +203,10 @@ class Redis(RedisBase):
) )
raise e raise e
self.info(f"Data held and melted has {len(data_hold_melted)} rows")
self.debug( self.debug(
f"Data grouped and held successfully:\n {data_hold_melted.to_string()}", f"Data held and melted:\n {data_hold_melted.to_string()}",
metadata=metadata metadata=metadata
) )

View File

@@ -1,12 +1,12 @@
from temporalio import workflow, client from temporalio import workflow, client
from temporalio.worker import Worker from temporalio.worker import Worker, PollerBehaviorAutoscaling
from temporalio.runtime import Runtime, TelemetryConfig, PrometheusConfig from temporalio.runtime import Runtime, TelemetryConfig, PrometheusConfig
with workflow.unsafe.imports_passed_through(): with workflow.unsafe.imports_passed_through():
import sys import sys
import os import os
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
from sientia_do.temporal.utils.logger import get_logger from sientia_do.observability.logger import get_logger
from scouter.activities.activities import Activities from scouter.activities.activities import Activities
from scouter.workflow.scouter import Scouter from scouter.workflow.scouter import Scouter
from scouter.workflow.sub_workflows.core_scouter import CoreScouter from scouter.workflow.sub_workflows.core_scouter import CoreScouter
@@ -30,12 +30,20 @@ async def main():
logger = get_logger(__name__) logger = get_logger(__name__)
logger.info(f"Starting Worker with pod_id: {POD_ID}") metadata = {
'pod_id': POD_ID,
'model_name': '-',
'model_id': '-',
'workflow_name': '-',
'schedule_name': '-',
}
logger.info("Starting prometheus client...") logger.custom_info(f"Starting Worker with pod_id: {POD_ID}", metadata)
logger.custom_info("Starting prometheus client...", metadata)
start_prometheus_server() start_prometheus_server()
logger.info('Starting Notification Handler...') logger.custom_info('Starting Notification Handler...', metadata)
mongo_config = build_mongodb_config() mongo_config = build_mongodb_config()
notification_handler = NotificationHandler( notification_handler = NotificationHandler(
@@ -45,7 +53,7 @@ async def main():
project_name=os.getenv('PROJECT_NAME', 'scouter') project_name=os.getenv('PROJECT_NAME', 'scouter')
) )
logger.info('Starting Activities...') logger.custom_info('Starting Activities...', metadata)
activities = Activities( activities = Activities(
logger=logger, logger=logger,
@@ -55,7 +63,7 @@ async def main():
mongodb_config=build_mongodb_config() mongodb_config=build_mongodb_config()
) )
logger.info('Starting Faker Activities...') logger.custom_info('Starting Faker Activities...', metadata)
faker_activities = Faker( faker_activities = Faker(
logger=logger, logger=logger,
@@ -64,7 +72,8 @@ async def main():
'KAFKA_BOOTSTRAP_SERVERS', 'localhost:9092') 'KAFKA_BOOTSTRAP_SERVERS', 'localhost:9092')
) )
logger.info(f'Starting SDK Metrics Server on port {SDK_METRICS_PORT}...') logger.custom_info(
f'Starting SDK Metrics Server on port {SDK_METRICS_PORT}...', metadata)
new_runtime = Runtime( new_runtime = Runtime(
telemetry=TelemetryConfig( telemetry=TelemetryConfig(
@@ -73,7 +82,7 @@ async def main():
) )
) )
logger.info('Starting Temporal Client...') logger.custom_info('Starting Temporal Client...', metadata)
temporal_client = await client.Client.connect( temporal_client = await client.Client.connect(
target_host=host, target_host=host,
@@ -81,7 +90,7 @@ async def main():
runtime=new_runtime runtime=new_runtime
) )
logger.info('Starting Workers...') logger.custom_info('Starting Workers...', metadata)
workers = [ workers = [
Worker( Worker(
@@ -99,11 +108,12 @@ async def main():
activities.write_metrics, activities.write_metrics,
activities.store_data_package, activities.store_data_package,
], ],
max_concurrent_workflow_tasks=100, max_concurrent_workflow_tasks=50,
max_concurrent_activities=100, max_concurrent_activities=50,
max_concurrent_local_activities=100, max_concurrent_local_activities=50,
max_concurrent_workflow_task_polls=100, max_cached_workflows=200,
max_cached_workflows=50, workflow_task_poller_behavior=PollerBehaviorAutoscaling(),
activity_task_poller_behavior=PollerBehaviorAutoscaling()
), ),
Worker( Worker(
temporal_client, temporal_client,
@@ -119,13 +129,14 @@ async def main():
for w in workers: for w in workers:
handlers.append(w.run()) handlers.append(w.run())
logger.info('Workers started successfully') logger.custom_info('Workers started successfully', metadata)
try: try:
await asyncio.gather(*handlers) await asyncio.gather(*handlers)
except BaseException as e: # NOSONAR except BaseException as e: # NOSONAR
logger.error("An unhandled exception occurred: %s", e, exc_info=True) logger.custom_error("An unhandled exception occurred: %s",
e, exc_info=True, metadata=metadata)
finally: finally:
if notification_handler: if notification_handler:
notification_handler.shutdown() notification_handler.shutdown()

View File

@@ -4,7 +4,7 @@ with workflow.unsafe.imports_passed_through():
from scouter.activities.faker import Faker from scouter.activities.faker import Faker
from datetime import timedelta from datetime import timedelta
from typing import Dict, Any from typing import Dict, Any
from sientia_do.temporal.utils.policies import retry_policy from sientia_do.temporal.policies import retry_policy
@workflow.defn(name="fake_data") @workflow.defn(name="fake_data")

View File

@@ -4,7 +4,7 @@ with workflow.unsafe.imports_passed_through():
from scouter.activities.activities import Activities from scouter.activities.activities import Activities
from typing import Any from typing import Any
from datetime import timedelta from datetime import timedelta
from sientia_do.temporal.utils.policies import retry_policy from sientia_do.temporal.policies import retry_policy
@workflow.defn(name="scouter") @workflow.defn(name="scouter")

View File

@@ -4,7 +4,7 @@ with workflow.unsafe.imports_passed_through():
from scouter.activities.activities import Activities from scouter.activities.activities import Activities
from typing import Any from typing import Any
from datetime import timedelta from datetime import timedelta
from sientia_do.temporal.utils.policies import retry_policy from sientia_do.temporal.policies import retry_policy
@workflow.defn(name="core_scouter") @workflow.defn(name="core_scouter")

View File

@@ -11,7 +11,7 @@ image:
# This sets the pull policy for images. # This sets the pull policy for images.
pullPolicy: Always pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion. # Overrides the image tag whose default is the chart appVersion.
tag: "0.4.0" tag: "0.4.2"
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ # This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
imagePullSecrets: imagePullSecrets:
@@ -150,7 +150,7 @@ env:
- name: GITHUB_REPO_URL - name: GITHUB_REPO_URL
value: "git@github.com:Aignosi/sientia-dataops-scouter_temporal.git" value: "git@github.com:Aignosi/sientia-dataops-scouter_temporal.git"
- name: GITHUB_BRANCH - name: GITHUB_BRANCH
value: "SIENTIAPDE-1169-pensar-e-projetar-testes-de-breakdown-e-performance" value: "SIENTIAPDE-1199-revisar-e-testar-observabilidade"
- name: PYTHON_APP - name: PYTHON_APP
value: "scouter.worker.worker" value: "scouter.worker.worker"