# Host Metrics on Windows

> Monitor Windows server metrics including CPU, memory, disk, network, and processes using OpenTelemetry collector with Last9

Source: https://last9.io/docs/integrations/observability/host-metrics-on-windows/

Use OpenTelemetry to monitor hostmetrics on Windows machines with Last9.

## Prerequisites

Before setting up Windows host metrics monitoring, ensure you have:

- Windows Server 2016 or later, or Windows 10/11
- Administrative access to your Windows server
- OpenTelemetry Collector installation access
- Last9 account with integration credentials

1.  **Install OpenTelemetry Collector**

    Download the OpenTelemetry Collector MSI installer from the following link:

    ```bash
    https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.118.0/otelcol-contrib_0.118.0_windows_x64.msi
    ```

2.  **Prerequisites for Log Collection**

    Before configuring log collection, ensure the following:

    ### Windows Event Logs

    Windows Event Logs are available by default. No additional configuration needed.

    ### IIS Logs (if applicable)

    If you want to collect IIS logs, ensure IIS is installed and logging is enabled:

    - Default IIS log location: `C:\inetpub\logs\LogFiles\W3SVC1\`
    - Verify logs are being written: `dir "C:\inetpub\logs\LogFiles\W3SVC1\"`

    ### Application Logs (if applicable)

    For custom application logs:

    - Identify the log file path (e.g., `E:\MyApp\logs\*.log`)
    - Ensure the OpenTelemetry Collector service account has read permissions

    ### SQL Server Logs (if applicable)

    If SQL Server is installed and you want to collect error logs:

    - Default SQL Server ERRORLOG location: `C:\Program Files\Microsoft SQL Server\MSSQL*.MSSQLSERVER\MSSQL\Log\ERRORLOG*`
    - SQL Server error logs use UTF-16 LE encoding
    - Ensure read permissions for the OpenTelemetry Collector service account

    ### File Permissions

    The OpenTelemetry Collector service runs under the `NT AUTHORITY\SYSTEM` account by default, which should have read access to most log files. If you encounter permission issues, run the following PowerShell command:

    ```powershell
    # Grant read permissions to a specific directory
    icacls "E:\path\to\logs" /grant "NT AUTHORITY\SYSTEM:(OI)(CI)R"
    ```

3.  **Configure OpenTelemetry Collector**

    Use the following configuration for Otel Collector. Create a `config.yaml` file at `C:\Program Files\OpenTelemetry Collector\config.yaml` with the following content:

    ```yaml
    receivers:
      # Windows Event Log receiver for System, Application, and Security logs
      windowseventlog:
        channel: System
        max_reads: 100
        start_at: end

      windowseventlog/application:
        channel: Application
        max_reads: 100
        start_at: end

      windowseventlog/security:
        channel: Security
        max_reads: 100
        start_at: end

      # IIS log receiver (if IIS is installed)
      filelog/iis:
        include:
          - 'C:\inetpub\logs\LogFiles\W3SVC*\*.log'
        include_file_path: true
        start_at: end
        retry_on_failure:
          enabled: true

      # Application log receiver (customize path as needed)
      filelog/application:
        include:
          - 'C:\MyApp\logs\*.log'
          - 'C:\Applications\**\*.log'
        include_file_path: true
        start_at: end
        retry_on_failure:
          enabled: true

      # SQL Server ERRORLOG receiver (if SQL Server is installed)
      filelog/sqlserver:
        include:
          - 'C:\Program Files\Microsoft SQL Server\MSSQL*.MSSQLSERVER\MSSQL\Log\ERRORLOG*'
        include_file_path: true
        # SQL Server ERRORLOG is UTF-16 LE; set encoding to avoid null-byte spacing
        encoding: utf-16le
        start_at: end
        retry_on_failure:
          enabled: true

      hostmetrics:
        collection_interval: 60s
        scrapers:
          cpu:
            metrics:
              system.cpu.logical.count:
                enabled: true
          memory:
            metrics:
              system.memory.utilization:
                enabled: true
              system.memory.limit:
                enabled: true
          disk:
          filesystem:
            metrics:
              system.filesystem.utilization:
                enabled: true
          network:
          paging:
          load:
          process:
            mute_process_user_error: true
            mute_process_io_error: true
            mute_process_exe_error: true
            metrics:
              process.cpu.utilization:
                enabled: true
              process.memory.utilization:
                enabled: true
    processors:
      batch:
        timeout: 20s
        send_batch_size: 10000
        send_batch_max_size: 10000

      resourcedetection/azure:
        detectors: [env, azure]
        timeout: 2s
        override: false

      resourcedetection/system:
        detectors: ["system"]
        system:
          hostname_sources: ["os"]
          resource_attributes:
            host.ip:
              enabled: true
            host.cpu.model.name:
              enabled: true

      transform/logs:
        log_statements:
          - context: resource
            statements:
              - set(attributes["service.name"], "windows-host") # Change this as needed
              - set(attributes["deployment.environment"], "production") # Change this as needed

      transform/hostmetrics:
        metric_statements:
          - context: datapoint
            statements:
              - set(attributes["host.name"], resource.attributes["host.name"])
              - set(attributes["cloud.account.id"], resource.attributes["cloud.account.id"])
              - set(attributes["cloud.availability_zone"], resource.attributes["cloud.availability_zone"])
              - set(attributes["cloud.platform"], resource.attributes["cloud.platform"])
              - set(attributes["cloud.provider"], resource.attributes["cloud.provider"])
              - set(attributes["cloud.region"], resource.attributes["cloud.region"])
              - set(attributes["host.type"], resource.attributes["host.type"])
              - set(attributes["host.image.id"], resource.attributes["host.image.id"])

    exporters:
      otlp/last9:
        endpoint: "{{ .Logs.WriteURL }}"
        headers:
          "Authorization": "{{ .Logs.AuthValue }}"
      debug:
        verbosity: detailed

    service:
      pipelines:
        logs:
          receivers:
            [
              windowseventlog,
              windowseventlog/application,
              windowseventlog/security,
              filelog/iis,
              filelog/application,
              filelog/sqlserver,
            ]
          processors:
            [
              batch,
              resourcedetection/system,
              resourcedetection/azure,
              transform/logs,
            ]
          exporters: [otlp/last9]
        metrics:
          receivers: [hostmetrics]
          processors:
            [
              batch,
              resourcedetection/system,
              resourcedetection/azure,
              transform/hostmetrics,
            ]
          exporters: [otlp/last9]
    ```

    > **Note:** The logs pipeline includes all log receivers. You can comment out or remove receivers for log sources that are not available on your system (e.g., if IIS or SQL Server are not installed).

4.  **Start OpenTelemetry Collector**

    ### Configuration File Location

    After installing the MSI, the config file should be placed in the installation directory:

    ```powershell
    C:\Program Files\OpenTelemetry Collector\config.yaml
    ```

    ### Start the OpenTelemetry Collector Service

    Instead of running the executable directly, you need to:

**PowerShell Service Management**

    Configure and Start Windows Service (Recommended):

    ```powershell
    # Set service to start automatically
    Set-Service -Name otelcol-contrib -StartupType Automatic

    # Start the service
    Start-Service otelcol-contrib

    # Check service status
    Get-Service otelcol-contrib

    # Stop the service
    Stop-Service otelcol-contrib

    # Restart the service
    Restart-Service otelcol-contrib
    ```

**Using sc.exe**

    Using sc.exe (Windows Service Control):

    > **Note:** If using sc.exe, ensure the service is configured with the correct config file path first.

    ```powershell
    # Start the service
    sc start otelcol-contrib

    # Check status
    sc query otelcol-contrib

    # Stop the service
    sc stop otelcol-contrib
    ```

    ### Additional Service Configuration Methods

    #### Configure the Service Binary Path with sc.exe

    ```cmd
    # View current service configuration
    sc qc otelcol-contrib

    # Modify the service to include config file path
    sc config otelcol-contrib binPath= "\"C:\Program Files\OpenTelemetry Collector\otelcol-contrib.exe\" --config \"C:\Program Files\OpenTelemetry Collector\config.yaml\""
    ```

    > **Important:** Note the space after `binPath=` - this is required by sc.exe syntax!

    #### During Service Installation

    If the service isn't installed yet or you need to reinstall:

    ```cmd
    # Create/Install the service with config path
    sc create otelcol-contrib binPath= "\"C:\Program Files\OpenTelemetry Collector\otelcol-contrib.exe\" --config \"C:\Program Files\OpenTelemetry Collector\config.yaml\" " start= auto DisplayName= "OpenTelemetry Collector Contrib"

    # Then start it
    sc start otelcol-contrib
    ```

    #### Using PowerShell

    ```powershell
    # View current configuration
    Get-CimInstance -ClassName Win32_Service -Filter "Name='otelcol-contrib'" | Select-Object Name, PathName

    # Modify the service
    $configPath = "C:\Program Files\OpenTelemetry Collector\config.yaml"
    $binPath = "`"C:\Program Files\OpenTelemetry Collector\otelcol-contrib.exe`" --config `"$configPath`""

    # Stop service first
    Stop-Service otelcol-contrib

    # Update the binary path
    $service = Get-WmiObject Win32_Service -Filter "Name='otelcol-contrib'"
    $service.Change($null, $binPath)

    # Start service
    Start-Service otelcol-contrib
    ```

    #### Configure Service to Start Automatically

    ```powershell
    # Set service to start automatically on boot
    Set-Service -Name otelcol-contrib -StartupType Automatic
    ```

    ### Customize Application Log Paths

    Update the `filelog/application` receiver to match your application's log locations:

    ```yaml
    filelog/application:
      include:
        - 'C:\YourApp\logs\*.log'
        - 'D:\Applications\MyService\logs\*.log'
        - 'C:\ProgramData\CustomApp\**\*.log'
    ```

## Verification

To verify the setup is working:

1. **View Service Logs:**

   ```powershell
   # Check Windows Event Viewer logs
   Get-EventLog -LogName Application -Source otelcol-contrib -Newest 50

   # Or open Event Viewer GUI
   eventvwr.msc
   # Navigate to: Windows Logs > Application
   ```

2. **Check Service Status:**

   ```powershell
   Get-Service -Name otelcol-contrib
   ```

3. **View Metrics and Logs in Last9:**

   View the hostmetrics and logs from the Windows machine in [Last9](https://app.last9.io):

   - **Metrics**: Look for metrics with prefix `system.*` (e.g., `system.cpu.utilization`, `system.memory.utilization`, `system.filesystem.utilization`)
   - **Logs**: Filter by `service.name="windows-host"` (or your custom service name) to view collected logs

## Need Help?

If you encounter any issues or have questions:

- Join our [Discord community](https://discord.com/channels/652153247672729619/652153247672729621) for real-time support
- Contact our support team at [support@last9.io](mailto:support@last9.io)
