388 lines
20 KiB
HTML
388 lines
20 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Integration Log - {{ log.system.name }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Breadcrumb -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="page-title-box d-sm-flex align-items-center justify-content-between">
|
|
<h4 class="mb-sm-0">Integration Log Detail</h4>
|
|
<div class="page-title-right">
|
|
<ol class="breadcrumb m-0">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'core:integration_log_list' %}">Integration Logs</a></li>
|
|
<li class="breadcrumb-item active">Log Detail</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Main Content -->
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-header bg-{% if log.level == 'DEBUG' %}secondary{% elif log.level == 'INFO' %}info{% elif log.level == 'WARNING' %}warning{% elif log.level == 'ERROR' %}danger{% elif log.level == 'CRITICAL' %}dark{% endif %} bg-opacity-25">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-shrink-0">
|
|
<div class="avatar-sm me-3">
|
|
<span class="avatar-title rounded-circle bg-{% if log.level == 'DEBUG' %}secondary{% elif log.level == 'INFO' %}info{% elif log.level == 'WARNING' %}warning{% elif log.level == 'ERROR' %}danger{% elif log.level == 'CRITICAL' %}dark{% endif %} text-white">
|
|
<i class="fas fa-{% if log.level == 'DEBUG' %}bug{% elif log.level == 'INFO' %}info{% elif log.level == 'WARNING' %}exclamation{% elif log.level == 'ERROR' %}times{% elif log.level == 'CRITICAL' %}radiation{% endif %}"></i>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h5 class="card-title mb-0">{{ log.system.name }}</h5>
|
|
<small class="text-muted">{{ log.timestamp|date:"F j, Y H:i:s" }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="d-flex mb-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-tag text-muted me-2"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">Level</h6>
|
|
<p class="mb-0">
|
|
<span class="badge bg-{% if log.level == 'DEBUG' %}secondary{% elif log.level == 'INFO' %}info{% elif log.level == 'WARNING' %}warning{% elif log.level == 'ERROR' %}danger{% elif log.level == 'CRITICAL' %}dark{% endif %}">
|
|
{{ log.level }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="d-flex mb-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-check-circle text-muted me-2"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">Status</h6>
|
|
<p class="mb-0">
|
|
<span class="badge bg-{% if log.status == 'success' %}success{% elif log.status == 'error' %}danger{% elif log.status == 'warning' %}warning{% else %}info{% endif %}">
|
|
{{ log.status|title }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Message</h6>
|
|
<div class="p-3 bg-light rounded">
|
|
{{ log.message|linebreaks }}
|
|
</div>
|
|
</div>
|
|
|
|
{% if log.request_data %}
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Request Data</h6>
|
|
<div class="p-3 bg-light rounded">
|
|
<pre class="mb-0"><code>{{ log.request_data|pprint }}</code></pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.response_data %}
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Response Data</h6>
|
|
<div class="p-3 bg-light rounded">
|
|
<pre class="mb-0"><code>{{ log.response_data|pprint }}</code></pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.error_details %}
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Error Details</h6>
|
|
<div class="p-3 bg-danger bg-opacity-10 rounded">
|
|
<pre class="mb-0 text-danger"><code>{{ log.error_details }}</code></pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.additional_data %}
|
|
<div class="mb-4">
|
|
<h6 class="text-muted mb-2">Additional Data</h6>
|
|
<div class="p-3 bg-light rounded">
|
|
<pre class="mb-0"><code>{{ log.additional_data|pprint }}</code></pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="row mb-0">
|
|
<div class="col-md-6">
|
|
<div class="d-flex mb-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-clock text-muted me-2"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">Timestamp</h6>
|
|
<p class="text-muted mb-0">{{ log.timestamp|date:"F j, Y H:i:s" }}</p>
|
|
<small class="text-muted">{{ log.timestamp|timesince }} ago</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="d-flex mb-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-stopwatch text-muted me-2"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">Duration</h6>
|
|
<p class="text-muted mb-0">
|
|
{% if log.duration %}
|
|
{{ log.duration }} ms
|
|
{% else %}
|
|
Not available
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Related Logs -->
|
|
{% if related_logs %}
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-link me-2"></i>
|
|
Related Logs
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Timestamp</th>
|
|
<th>Level</th>
|
|
<th>Status</th>
|
|
<th>Message</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for related_log in related_logs %}
|
|
<tr>
|
|
<td>{{ related_log.timestamp|date:"M d, Y H:i:s" }}</td>
|
|
<td>
|
|
<span class="badge bg-{% if related_log.level == 'DEBUG' %}secondary{% elif related_log.level == 'INFO' %}info{% elif related_log.level == 'WARNING' %}warning{% elif related_log.level == 'ERROR' %}danger{% elif related_log.level == 'CRITICAL' %}dark{% endif %}">
|
|
{{ related_log.level }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{% if related_log.status == 'success' %}success{% elif related_log.status == 'error' %}danger{% elif related_log.status == 'warning' %}warning{% else %}info{% endif %}">
|
|
{{ related_log.status|title }}
|
|
</span>
|
|
</td>
|
|
<td>{{ related_log.message|truncatechars:50 }}</td>
|
|
<td>
|
|
<a href="{% url 'core:integration_log_detail' related_log.pk %}" class="btn btn-sm btn-outline-primary">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- Quick Actions -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-bolt me-2"></i>
|
|
Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="{% url 'core:integration_log_list' %}" class="btn btn-outline-primary">
|
|
<i class="fas fa-arrow-left me-2"></i>
|
|
Back to Logs
|
|
</a>
|
|
|
|
<button type="button" class="btn btn-outline-info" onclick="copyLogId('{{ log.pk }}')">
|
|
<i class="fas fa-copy me-2"></i>
|
|
Copy Log ID
|
|
</button>
|
|
|
|
<a href="{% url 'core:export_integration_log' log.pk %}" class="btn btn-outline-success">
|
|
<i class="fas fa-file-export me-2"></i>
|
|
Export Log
|
|
</a>
|
|
|
|
{% if log.status == 'error' %}
|
|
<a href="{% url 'core:retry_integration' log.pk %}" class="btn btn-outline-warning">
|
|
<i class="fas fa-redo me-2"></i>
|
|
Retry Operation
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-server me-2"></i>
|
|
System Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="flex-shrink-0">
|
|
<div class="avatar-sm me-3">
|
|
<span class="avatar-title rounded-circle bg-primary text-white">
|
|
{{ log.system.name|first|upper }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">{{ log.system.name }}</h6>
|
|
<small class="text-muted">{{ log.system.get_system_type_display }}</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<tbody>
|
|
<tr>
|
|
<td style="width: 120px;"><i class="fas fa-link me-2"></i> API URL</td>
|
|
<td>{{ log.system.api_url|default:"Not available" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-check-circle me-2"></i> Status</td>
|
|
<td>
|
|
<span class="badge bg-{% if log.system.is_active %}success{% else %}danger{% endif %}">
|
|
{% if log.system.is_active %}Active{% else %}Inactive{% endif %}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-heartbeat me-2"></i> Health</td>
|
|
<td>
|
|
<span class="badge bg-{% if log.system.health_status == 'healthy' %}success{% elif log.system.health_status == 'degraded' %}warning{% elif log.system.health_status == 'down' %}danger{% else %}secondary{% endif %}">
|
|
{{ log.system.health_status|default:"Unknown"|title }}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-sync-alt me-2"></i> Last Sync</td>
|
|
<td>{{ log.system.last_sync|default:"Never"|date:"M d, Y H:i:s" }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
<a href="{% url 'integration:external_system_detail' log.system.pk %}" class="btn btn-sm btn-outline-primary">
|
|
<i class="fas fa-external-link-alt me-1"></i>
|
|
View System Details
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Log Metadata -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Log Metadata
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<tbody>
|
|
<tr>
|
|
<td style="width: 120px;"><i class="fas fa-fingerprint me-2"></i> Log ID</td>
|
|
<td>
|
|
<code>{{ log.pk }}</code>
|
|
<button class="btn btn-sm btn-link p-0 ms-2" onclick="copyLogId('{{ log.pk }}')">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-user me-2"></i> User</td>
|
|
<td>{{ log.user|default:"System" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-code me-2"></i> API Version</td>
|
|
<td>{{ log.api_version|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-exchange-alt me-2"></i> Direction</td>
|
|
<td>
|
|
{% if log.direction == 'inbound' %}
|
|
<span class="badge bg-info">Inbound</span>
|
|
{% elif log.direction == 'outbound' %}
|
|
<span class="badge bg-primary">Outbound</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">Internal</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-network-wired me-2"></i> IP Address</td>
|
|
<td>{{ log.ip_address|default:"Not available" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-hashtag me-2"></i> HTTP Status</td>
|
|
<td>
|
|
{% if log.http_status %}
|
|
<span class="badge bg-{% if log.http_status >= 200 and log.http_status < 300 %}success{% elif log.http_status >= 300 and log.http_status < 400 %}info{% elif log.http_status >= 400 and log.http_status < 500 %}warning{% elif log.http_status >= 500 %}danger{% else %}secondary{% endif %}">
|
|
{{ log.http_status }}
|
|
</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">N/A</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><i class="fas fa-building me-2"></i> Tenant</td>
|
|
<td>{{ log.tenant|default:"System-wide" }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
function copyLogId(logId) {
|
|
navigator.clipboard.writeText(logId).then(function() {
|
|
alert('Log ID copied to clipboard: ' + logId);
|
|
}, function() {
|
|
alert('Failed to copy log ID');
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|