Files
..
2026-01-28 10:29:49 -06:00
2026-01-28 10:29:49 -06:00
2026-01-28 10:29:49 -06:00
2026-01-28 10:29:49 -06:00
2026-01-28 10:29:49 -06:00

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 installed and configured
  • .NET 8 SDK
  • Azure subscription with appropriate permissions
  • Grafana 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

# 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

# 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:

# 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:

// 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

cd BlazorApp
dotnet run

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

Configuration

appsettings.json

Configure logging levels and Application Insights:

{
  "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

// 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

@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:

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

Resources

License

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