# Blazor Server App with Grafana Observability Stack

This project provides a complete infrastructure-as-code setup for deploying a Blazor Server application to Azure with comprehensive logging and metrics capabilities for use with Grafana.

## Architecture

The solution includes:

- **Azure App Service** - Hosting the Blazor Server application
- **Application Insights** - Azure-native monitoring and telemetry
- **Log Analytics Workspace** - Centralized logging
- **Prometheus Metrics** - Exposed at `/metrics` endpoint
- **OpenTelemetry** - Distributed tracing support
- **Serilog** - Structured logging

## Project Structure

```
.
├── main.bicep                          # Main Bicep file (subscription-level)
├── modules/
│   ├── monitoring.bicep                # Log Analytics & Application Insights
│   └── appService.bicep                # App Service Plan & Web App
├── BlazorApp/                          # Blazor Server application
│   ├── Components/
│   │   ├── Layout/
│   │   │   ├── MainLayout.razor
│   │   │   └── NavMenu.razor
│   │   └── Pages/
│   │       ├── Home.razor
│   │       ├── Metrics.razor           # Metrics demo page
│   │       └── Logs.razor              # Logging demo page
│   ├── Program.cs                      # App configuration
│   ├── BlazorApp.csproj               # Project file with dependencies
│   └── appsettings.json               # Configuration
├── deploy.sh                           # Deployment script
└── README.md                           # This file
```

## Prerequisites

- [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli) installed and configured
- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)
- Azure subscription with appropriate permissions
- [Grafana](https://grafana.com/) instance (can be Azure Managed Grafana or self-hosted)

## Features

### Logging
- **Serilog** for structured logging with console and file outputs
- **Application Insights** integration for Azure-native logging
- Log levels: Information, Warning, Error
- Structured log properties for better querying

### Metrics
- **Prometheus** metrics exposed at `/metrics` endpoint
- **OpenTelemetry** instrumentation for ASP.NET Core and HTTP clients
- Custom metrics tracking (counters, timers)
- Health check endpoint at `/health`

### Demo Pages
- **Home** - Overview and quick log generation
- **Metrics** - Interactive metrics demonstration
- **Logs** - Test different log levels and structured logging

## Deployment

### 1. Deploy Azure Infrastructure

```bash
# Login to Azure
az login

# Run the deployment script
./deploy.sh
```

This will create:
- Resource Group
- App Service Plan (Basic B1 tier)
- Web App (Linux, .NET 8)
- Application Insights
- Log Analytics Workspace

### 2. Build and Deploy the Application

```bash
# Navigate to the app directory
cd BlazorApp

# Restore dependencies
dotnet restore

# Build the application
dotnet build

# Publish the application
dotnet publish -c Release -o ./publish

# Create deployment package
cd publish
zip -r ../app.zip .
cd ..

# Deploy to Azure
az webapp deployment source config-zip \
  --resource-group rg-blazor-grafana \
  --name <your-webapp-name> \
  --src app.zip
```

### 3. Verify Deployment

Once deployed, you can access:
- **Application**: `https://<your-webapp-name>.azurewebsites.net`
- **Metrics**: `https://<your-webapp-name>.azurewebsites.net/metrics`
- **Health Check**: `https://<your-webapp-name>.azurewebsites.net/health`

## Grafana Integration

### Option 1: Prometheus Data Source

1. In Grafana, add a new Prometheus data source
2. Set the URL to: `https://<your-webapp-name>.azurewebsites.net`
3. Configure scrape interval (e.g., 15s)
4. Save and test the connection

### Option 2: Azure Monitor Data Source

1. In Grafana, add an Azure Monitor data source
2. Configure with your Azure subscription details
3. Point to your Application Insights instance
4. You'll have access to:
   - Application logs
   - Traces
   - Metrics
   - Dependencies

### Creating Dashboards

**Sample Queries for Prometheus:**
```promql
# Request rate
rate(http_requests_received_total[5m])

# Request duration
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# Error rate
rate(http_requests_received_total{status_code=~"5.."}[5m])
```

**Sample Queries for Azure Monitor:**
```kusto
// Application logs
traces
| where timestamp > ago(1h)
| project timestamp, message, severityLevel

// Request performance
requests
| where timestamp > ago(1h)
| summarize avg(duration), percentile(duration, 95) by bin(timestamp, 5m)

// Custom events
customEvents
| where timestamp > ago(1h)
| summarize count() by name
```

## Available Metrics

The application exposes the following metrics at `/metrics`:

- `http_requests_received_total` - Total HTTP requests received
- `http_request_duration_seconds` - HTTP request duration histogram
- `http_requests_in_progress` - Current HTTP requests in progress
- `process_cpu_seconds_total` - Process CPU time
- `process_working_set_bytes` - Process memory usage
- `dotnet_*` - Various .NET runtime metrics

## Local Development

```bash
cd BlazorApp
dotnet run
```

Access the app at `https://localhost:5001` or `http://localhost:5000`

## Configuration

### appsettings.json

Configure logging levels and Application Insights:

```json
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning"
      }
    }
  },
  "ApplicationInsights": {
    "ConnectionString": "your-connection-string"
  }
}
```

### Environment Variables

The following environment variables are automatically set in Azure:
- `APPLICATIONINSIGHTS_CONNECTION_STRING`
- `APPINSIGHTS_INSTRUMENTATIONKEY`
- `ASPNETCORE_ENVIRONMENT`

## Customization

### Adding Custom Metrics

```csharp
// In your Razor component
@using Prometheus

private static readonly Counter CustomCounter = Metrics
    .CreateCounter("myapp_custom_counter", "Description");

private void MyMethod()
{
    CustomCounter.Inc();
}
```

### Adding Custom Logs

```csharp
@inject ILogger<MyComponent> Logger

Logger.LogInformation("User {UserId} performed action {Action}", 
    userId, actionName);
```

## Monitoring Best Practices

1. **Use structured logging** - Always use parameterized log messages
2. **Set appropriate log levels** - Don't overuse Information level
3. **Add context** - Include relevant properties in logs
4. **Monitor error rates** - Set up alerts in Grafana
5. **Track business metrics** - Not just technical metrics
6. **Use distributed tracing** - Leverage OpenTelemetry spans

## Troubleshooting

### Application Insights not receiving data
- Check the connection string in Azure portal
- Verify Application Insights instrumentation key
- Check network connectivity from App Service

### Prometheus metrics not showing
- Ensure `/metrics` endpoint is accessible
- Check if Prometheus is configured correctly in Grafana
- Verify App Service networking rules

### Logs not appearing
- Check Log Analytics workspace connection
- Verify Serilog configuration
- Check file permissions for log files

## Cost Considerations

This setup uses:
- App Service Plan: Basic B1 (~$55/month)
- Application Insights: Pay-as-you-go (first 5GB free)
- Log Analytics: Pay-as-you-go (first 5GB free)

To reduce costs:
- Use Free tier App Service for testing
- Adjust log retention periods
- Implement sampling in Application Insights

## Clean Up

To delete all resources:

```bash
az group delete --name rg-blazor-grafana --yes --no-wait
```

## Resources

- [Blazor Documentation](https://docs.microsoft.com/aspnet/core/blazor/)
- [Application Insights](https://docs.microsoft.com/azure/azure-monitor/app/app-insights-overview)
- [Prometheus](https://prometheus.io/docs/introduction/overview/)
- [Grafana](https://grafana.com/docs/)
- [OpenTelemetry](https://opentelemetry.io/docs/)
- [Serilog](https://serilog.net/)

## License

This project is provided as-is for educational and demonstration purposes.
