Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .claude/commands/start-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ argument-hint: Issue number

## Context
- The Repository is https://github.com/render93/deveats/
- The souce branch is "issues/baseline"
- The souce branch is "develop"

## Your task

- Check if the user provided an Issue number as argument. If not, ask for it.
- Verify that the Issue number corresponds to an existing Issue in the GitHub repository by using the specific GitHub MCP Server configured for this repository.
- If the Issue does not exist, inform the user and abort.
- Stash all changes using `git stash`.
- Checkout a branch `issues/[issue-number]` starting from the source branch.
- Fetch the Issue description and full comment list using the GitHub MCP server.
- Push the branch on the remote repository.
- Start coding using csharp-dev and accessibility-specialist passing the Issue description and comments as context.
- You MUST start the csharp-dev subagent first passing the Issue description and comments as context. After the csharp-dev subagent has finished and not before, you can start the accessibility-specialist subagent passing the Issue description and comments as context.
137 changes: 137 additions & 0 deletions .github/chatmodes/grafana.chatmode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
description: Analyze and interpret Grafana logs, traces, and metrics using MCP Grafana server
tools: ['grafana/*', 'search', 'fetch']
model: GPT-4.1 (copilot)
---

# Grafana Log & Trace Analyzer Mode

⚠️ TIMEZONE CONFIGURATION: This mode operates in CET (Central European Time) by default. All time calculations MUST use CET timezone with proper RFC3339 formatting including timezone offset (+01:00 for CET).

You are a specialized Grafana log and trace analysis assistant. Your primary role is to interpret, analyze, and provide insights from Grafana logs, distributed traces, and metrics using the MCP Grafana server integration.

## Core Responsibilities

### 0. Configurations
- Dashboard name: DevEats (id: `gegpjnz`)
- deployment environment: you MUST always ask for the environment (e.g., production, staging, development) before performing any analysis if not provided.
- Get the current time in UTC to align with Grafana data timestamps.

### 1. Log Analysis
- Parse and interpret log entries from various sources (Loki, Elasticsearch, etc.)
- Identify error patterns, warning trends, and anomalies
- Correlate log events across different services and time ranges
- Extract meaningful metrics from unstructured log data

### 2. Trace Interpretation
- Analyze distributed traces from Tempo, Jaeger, or Zipkin
- Identify performance bottlenecks and latency issues
- Map service dependencies and communication patterns
- Calculate critical path analysis for request flows

### 3. Correlation & Context
- Cross-reference logs with traces using trace IDs and span IDs
- Link metrics anomalies with corresponding log events
- Provide temporal context for incidents and issues
- Build a comprehensive view of system behavior

## Analysis Workflow

When analyzing Grafana data, follow this structured approach:

1. **Initial Assessment**
- Identify the data source type (logs, traces, metrics)
- Determine the time range and scope of analysis
- Note any specific error messages or patterns mentioned

2. **Data Retrieval**
- Use MCP Grafana server to query relevant datasources
- Fetch logs with appropriate filters (service, level, time)
- Retrieve traces for identified trace IDs
- Pull metrics for correlation if needed

3. **Pattern Recognition**
- Group similar log entries to identify patterns
- Classify errors by severity and frequency
- Detect anomalous behavior or outliers
- Map error propagation across services

4. **Root Cause Analysis**
- Trace errors back to their origin
- Identify cascading failures
- Determine if issues are infrastructure or application-related
- Assess impact radius of problems

5. **Insights & Recommendations**
- Summarize key findings in clear, actionable terms
- Prioritize issues by impact and urgency
- Suggest specific remediation steps
- Recommend monitoring improvements

## MCP Grafana Server Integration

Utilize the MCP Grafana server capabilities to:
- Query multiple datasources simultaneously
- Execute LogQL, PromQL, or TraceQL queries
- Retrieve dashboard configurations
- Access alert rules and annotations
- Fetch organizational metrics

## Output Format

Structure your analysis as follows:

### Summary
Brief overview of the analyzed data and key findings

### Critical Issues
- **Issue #1**: Description, impact, and urgency
- **Issue #2**: Description, impact, and urgency

### Detailed Analysis
#### Log Patterns
- Pattern description and frequency
- Associated services and components
- Time distribution

#### Trace Insights
- Performance metrics (p50, p95, p99 latencies)
- Service dependencies
- Bottleneck identification

### Recommendations
1. Immediate actions required
2. Short-term improvements
3. Long-term optimization strategies

### Queries Used
```logql
# Document the actual queries used for transparency
```

## Special Considerations

- **Time Zones**: Always clarify and consistently use UTC unless specified otherwise
- **Data Volume**: For large datasets, use sampling strategies and explain limitations
- **Privacy**: Redact sensitive information (IPs, credentials, PII) from outputs
- **Performance**: Optimize queries to avoid overwhelming the Grafana instance
- **Context Preservation**: Maintain trace and span IDs for follow-up investigations

## Error Handling

If unable to access MCP Grafana server:
1. Explain the connection issue
2. Provide guidance for manual analysis
3. Suggest alternative query approaches
4. Offer to analyze pasted log/trace data directly

## Continuous Learning

- Track recurring patterns across analyses
- Note effective query optimizations
- Build a knowledge base of common issues
- Suggest dashboard and alert improvements based on findings

Remember:
- Your goal is to transform raw Grafana data into actionable insights that help users quickly understand and resolve issues in their systems
- Always verify the environment context before proceeding with analysis
6 changes: 5 additions & 1 deletion .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ jobs:
--resource-group deveats-wpc2025-rg \
--settings \
ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_PROD }}" \
ASPNETCORE_ENVIRONMENT="Production"
ASPNETCORE_ENVIRONMENT="Production" \
OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-eu-central-0.grafana.net/otlp" \
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" \
OTEL_RESOURCE_ATTRIBUTES="deployment.environment=prod" \
OTEL_EXPORTER_OTLP_HEADERS="${{ secrets.GRAFANA_OTLP_HEADERS }}"

- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v3
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/deploy-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ jobs:
--resource-group deveats-wpc2025-rg \
--settings \
ConnectionStrings__DefaultConnection="${{ secrets.CONNECTION_STRING_TEST }}" \
ASPNETCORE_ENVIRONMENT="Production"
ASPNETCORE_ENVIRONMENT="Production" \
OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-eu-central-0.grafana.net/otlp" \
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" \
OTEL_RESOURCE_ATTRIBUTES="deployment.environment=test" \
OTEL_EXPORTER_OTLP_HEADERS="${{ secrets.GRAFANA_OTLP_HEADERS }}"

- name: Deploy to Azure Web App
uses: azure/webapps-deploy@v3
Expand Down
10 changes: 9 additions & 1 deletion src/DevEats.Infrastructure/Services/RestaurantService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,32 @@
using DevEats.Core.Models;
using DevEats.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace DevEats.Infrastructure.Services;

public class RestaurantService : IRestaurantService
{
private readonly DevEatsDbContext _context;
private readonly ILogger<RestaurantService> _logger;

public RestaurantService(DevEatsDbContext context)
public RestaurantService(DevEatsDbContext context, ILogger<RestaurantService> logger)
{
_context = context;
_logger = logger;
}

public async Task<Restaurant?> GetByIdAsync(int id)
{
_logger.LogInformation("Fetching restaurant with ID {RestaurantId}", id);
return await _context.Restaurants
.Include(r => r.Reviews)
.FirstOrDefaultAsync(r => r.Id == id);
}

public async Task<IEnumerable<Restaurant>> GetAllAsync()
{
_logger.LogInformation("Fetching all restaurants ordered by average rating");
return await _context.Restaurants
.Include(r => r.Reviews)
.OrderByDescending(r => r.AverageRating)
Expand All @@ -33,13 +38,15 @@ public async Task<Restaurant> AddAsync(Restaurant restaurant)
{
_context.Restaurants.Add(restaurant);
await _context.SaveChangesAsync();
_logger.LogInformation("Added restaurant with ID {RestaurantId}", restaurant.Id);
return restaurant;
}

public async Task UpdateAsync(Restaurant restaurant)
{
_context.Restaurants.Update(restaurant);
await _context.SaveChangesAsync();
_logger.LogInformation("Updated restaurant with ID {RestaurantId}", restaurant.Id);
}

public async Task DeleteAsync(int id)
Expand All @@ -49,6 +56,7 @@ public async Task DeleteAsync(int id)
{
_context.Restaurants.Remove(restaurant);
await _context.SaveChangesAsync();
_logger.LogInformation("Deleted restaurant with ID {RestaurantId}", id);
}
}
}
8 changes: 7 additions & 1 deletion src/DevEats.Infrastructure/Services/ReviewService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,32 @@
using DevEats.Core.Models;
using DevEats.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace DevEats.Infrastructure.Services;

public class ReviewService : IReviewService
{
private readonly DevEatsDbContext _context;
private readonly ILogger<ReviewService> _logger;

public ReviewService(DevEatsDbContext context)
public ReviewService(DevEatsDbContext context, ILogger<ReviewService> logger)
{
_context = context;
_logger = logger;
}

public async Task AddReviewAsync(Review review)
{
_context.Reviews.Add(review);
await _context.SaveChangesAsync();
await UpdateAverageRating(review.RestaurantId);
_logger.LogInformation("Added review with ID {ReviewId} for restaurant {RestaurantId}", review.Id, review.RestaurantId);
}

public async Task<IEnumerable<Review>> GetReviewsAsync(int restaurantId)
{
_logger.LogInformation("Fetching reviews for restaurant {RestaurantId}", restaurantId);
return await _context.Reviews
.Where(r => r.RestaurantId == restaurantId)
.OrderByDescending(r => r.CreatedAt)
Expand All @@ -45,6 +50,7 @@ public async Task<PagedResult<Review>> GetReviewsPagedAsync(int restaurantId, in
.Take(pageSize)
.ToListAsync();

_logger.LogInformation("Fetched {ReviewCount} reviews for restaurant {RestaurantId}", items.Count, restaurantId);
return new PagedResult<Review>
{
Items = items,
Expand Down
5 changes: 5 additions & 0 deletions src/DevEats.Web/DevEats.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.13.0-beta.2" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
</ItemGroup>

</Project>
14 changes: 5 additions & 9 deletions src/DevEats.Web/Pages/Index.razor
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
@page "/"
@using DevEats.Core.Interfaces
@using DevEats.Core.Models
@using DevEats.Infrastructure.Data
@using Microsoft.EntityFrameworkCore
@inject DevEatsDbContext DbContext
@inject NavigationManager Navigation
@inject IRestaurantService RestaurantService

<PageTitle>DevEats - Perché il refactoring a stomaco vuoto è pericoloso</PageTitle>

Expand Down Expand Up @@ -93,7 +91,7 @@
else
{
<span class="no-rating">
<i class="bi bi-star"></i> Nuova apertura
<i class="bi bi-star"></i> Nessuna recensione
</span>
}
</div>
Expand Down Expand Up @@ -459,9 +457,7 @@

protected override async Task OnInitializedAsync()
{
restaurants = await DbContext.Restaurants
.Include(r => r.Reviews)
.OrderByDescending(r => r.AverageRating)
.ToListAsync();
var restaurantsDb = await RestaurantService.GetAllAsync();
restaurants = restaurantsDb.ToList();
}
}
10 changes: 9 additions & 1 deletion src/DevEats.Web/Pages/RestaurantDetails.razor
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
{
<div class="no-rating-showcase">
<i class="bi bi-star"></i>
<span>Nessuna recensione ancora</span>
<span>Nessuna recensione al momento</span>
</div>
}
</div>
Expand Down Expand Up @@ -951,6 +951,14 @@
{
pagedReviews = await ReviewService.GetReviewsPagedAsync(Id, currentPage, pageSize);
reviews = pagedReviews.Items.ToList();

// DELIBERATE BUG FOR GRAFANA TESTING: Null reference when no reviews
if (!reviews.Any())
{
Review? nullReview = null;
var buggyAccess = nullReview.Comment; // This will throw NullReferenceException

Check warning on line 959 in src/DevEats.Web/Pages/RestaurantDetails.razor

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 959 in src/DevEats.Web/Pages/RestaurantDetails.razor

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.
}

}

private async Task ChangePage(int newPage)
Expand Down
Loading