fix(observability): use LOG_DIR env for file logging, add RBAC for K8s job dispatch

- init_observability now reads LOG_DIR env var for log directory (falls back
  to relative logs/ path). Gracefully disables file logging if directory
  cannot be created instead of failing the entire observability init.
- Add ServiceAccount, Role, and RoleBinding for ml-training-service to
  create/get/list/watch/delete batch/v1 Jobs (K8s training dispatch).
- Add LOG_DIR=/app/logs env to ml-training-service, trading-service, and
  backtesting-service deployment YAMLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-02-28 21:21:13 +01:00
parent 6d7684a0c5
commit ada33cf181
5 changed files with 64 additions and 3 deletions

View File

@@ -110,13 +110,22 @@ pub async fn init_observability(
service_name: &str,
otlp_endpoint: &str,
) -> CommonResult<()> {
// Initialize JSON logger with default configuration
// Determine log directory from environment.
// In K8s pods, LOG_DIR is typically set to /app/logs (backed by an emptyDir volume).
// Locally, falls back to logs/<service_name>.
let log_dir = std::env::var("LOG_DIR")
.map(|d| format!("{}/{}", d, service_name))
.unwrap_or_else(|_| format!("logs/{}", service_name));
// Disable file logging if the directory cannot be created (e.g. read-only fs).
let enable_file = std::fs::create_dir_all(&log_dir).is_ok();
let logger_config = JsonLoggerConfig {
service_name: service_name.to_string(),
log_level: LogLevel::Info,
enable_console: true,
enable_file: true,
log_directory: format!("logs/{}", service_name),
enable_file,
log_directory: log_dir,
rotation: logger::LogRotation::Daily,
max_files: 10,
max_file_size_mb: 100,

View File

@@ -108,6 +108,8 @@ spec:
value: "placeholder"
- name: RUST_LOG
value: info
- name: LOG_DIR
value: /app/logs
volumeMounts:
- name: binaries
mountPath: /binaries

View File

@@ -24,6 +24,7 @@ spec:
labels:
app.kubernetes.io/name: ml-training-service
spec:
serviceAccountName: ml-training-service
nodeSelector:
k8s.scaleway.com/pool-name: gpu-inference
tolerations:
@@ -119,6 +120,8 @@ spec:
value: "true"
- name: RUST_LOG
value: info
- name: LOG_DIR
value: /app/logs
volumeMounts:
- name: binaries
mountPath: /binaries

View File

@@ -1,3 +1,45 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ml-training-service
namespace: foxhunt
labels:
app.kubernetes.io/name: ml-training-service
app.kubernetes.io/part-of: foxhunt
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ml-training-job-manager
namespace: foxhunt
labels:
app.kubernetes.io/name: ml-training-service
app.kubernetes.io/part-of: foxhunt
rules:
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["create", "get", "list", "watch", "delete"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ml-training-job-manager
namespace: foxhunt
labels:
app.kubernetes.io/name: ml-training-service
app.kubernetes.io/part-of: foxhunt
subjects:
- kind: ServiceAccount
name: ml-training-service
namespace: foxhunt
roleRef:
kind: Role
name: ml-training-job-manager
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -21,6 +63,7 @@ spec:
labels:
app.kubernetes.io/name: ml-training-service
spec:
serviceAccountName: ml-training-service
imagePullSecrets:
- name: scw-registry
nodeSelector:
@@ -122,6 +165,8 @@ spec:
optional: true
- name: RUST_LOG
value: info
- name: LOG_DIR
value: /app/logs
volumeMounts:
- name: binaries
mountPath: /binaries

View File

@@ -121,6 +121,8 @@ spec:
value: "50051"
- name: RUST_LOG
value: info
- name: LOG_DIR
value: /app/logs
volumeMounts:
- name: binaries
mountPath: /binaries