Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login
    Introducing Netgate Nexus: Multi-Instance Management at Your Fingertips.

    Squid Realtime Status by way if sqlight SQStat

    Scheduled Pinned Locked Moved Cache/Proxy
    sqlite3squidspeed
    1 Posts 1 Posters 123 Views 1 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • JonathanLeeJ Offline
      JonathanLee
      last edited by JonathanLee

      I wanted to share this with anyone else that noticed the speed when you hover over connections on status shows 0/0 always. Just in case also if anyone has any recommendations let me know.

      sqstat.class.php - Changes Log

      pfSense Squid Realtime Stats (SQStat) Speed Fix
      Date: March 12, 2026

      PROBLEM SUMMARY

      Current Speed and Avg Speed columns always showed 0 in SQStat.
      Three root causes were identified and fixed.


      CHANGE 1: Connection ID Key (both makeHtmlReport and parseRequest)

      LOCATION: makeHtmlReport (~line 341) and parseRequest (~line 499)

      BEFORE:
      $con_id = $con['connection'];

      AFTER:
      $con_id = md5($con['uri'] . $con['peer']);

      WHY:
      Squid reports connection IDs as memory addresses (e.g. 0xbe97ec98)
      which change on every request. This meant the session key for a
      connection never matched between page loads, so previous byte counts
      could never be found and current speed was always 0.
      Using md5(uri + peer) creates a stable, consistent key that matches
      the same connection across multiple refreshes.


      CHANGE 2: Session replaced with temp file (both functions)

      LOCATION: makeHtmlReport (~line 280) and parseRequest (~line 460)

      BEFORE (session read):
      unset($session_data);
      if (isset($_SESSION['time']) && ((time() - $_SESSION['time']) < 3*60)
      && isset($_SESSION['sqdata']) && is_array($_SESSION['sqdata'])) {
      $session_data = $_SESSION['sqdata'];
      }

      AFTER (file read):
      $sqstat_file = '/tmp/sqstat_data.json';
      $session_data = array();
      if (file_exists($sqstat_file) && (time() - filemtime($sqstat_file)) < 180) {
      $session_data = json_decode(file_get_contents($sqstat_file), true) ?: array();
      }

      BEFORE (session write):
      $_SESSION['time'] = time();
      if (isset($new_data)) {
      $_SESSION['sqdata'] = $new_data;
      }

      AFTER (file write):
      if (isset($new_data)) {
      file_put_contents($sqstat_file, json_encode($new_data));
      }

      WHY:
      pfSense uses jQuery AJAX to refresh SQStat. Each AJAX call was
      receiving a new PHP session ID, meaning $_SESSION was always empty
      on every refresh. Data written to $_SESSION on one call was never
      available on the next call. This was confirmed by debug logging
      showing a different session_id() on every request.
      /tmp on pfSense is a tmpfs (RAM) filesystem so writing to
      /tmp/sqstat_data.json has zero SSD impact and persists correctly
      between AJAX calls.


      CHANGE 3: Session start blocks removed (both functions)

      LOCATION: makeHtmlReport (~line 213) and parseRequest (~line 395)

      BEFORE:
      if ($this->use_sessions) {
      if (session_status() == PHP_SESSION_NONE) {
      session_name('SQDATA');
      session_start();
      }
      }

      AFTER:
      (removed entirely)

      WHY:
      pfSense already starts its own PHP session before SQStat loads.
      Attempting to start a second session named 'SQDATA' was conflicting
      with pfSense's session management. Since we moved to file-based
      storage this code is no longer needed at all.


      CHANGE 4: Avg speed moved outside session check (parseRequest)

      LOCATION: parseRequest (~line 520)

      BEFORE:
      if (isset($session_data[$con_id]) && !empty($session_data[$con_id])) {
      // ... curr_speed calculation ...
      // avg speed
      $avg_speed = $con['bytes'] / 1024;
      if ($con['seconds'] > 0) {
      $avg_speed /= $con['seconds'];
      }
      }

      AFTER:
      if (isset($session_data[$con_id])) {
      // ... curr_speed calculation only ...
      }
      // avg speed - always calculate
      if ($con['bytes'] > 0 && $con['seconds'] > 0) {
      $avg_speed = ($con['bytes'] / 1024) / $con['seconds'];
      }

      WHY:
      Avg speed does not need previous request data - it can always be
      calculated as total bytes transferred divided by connection duration.
      By moving it outside the session/file data check it shows immediately
      on first load for any connection alive more than 1 second, without
      needing a previous snapshot.


      CHANGE 5: Current speed calculation simplified (both functions)

      LOCATION: makeHtmlReport (~line 345) and parseRequest (~line 503)

      BEFORE:
      if ($was_time && $was_size) {
      $delta = $is_time - $was_time;
      if ($delta == 0) {
      $delta = 1;
      }
      if ($con['bytes'] >= $was_size) {
      $curr_speed = ($con['bytes'] - $was_size) / 1024 / $delta;
      }
      } else {
      $curr_speed = $con['bytes'] / 1024;
      }

      AFTER:
      $delta_time = max(1, $is_time - $was_time);
      $delta_bytes = $con['bytes'] - $was_size;
      if ($delta_bytes > 0) {
      $curr_speed = ($delta_bytes / 1024) / $delta_time;
      }

      WHY:
      Simplified the delta calculation using max(1, ...) to avoid division
      by zero more cleanly. Removed the fallback that set curr_speed to
      total bytes when no previous size was recorded - that was showing
      inflated incorrect values. Now only shows current speed when there
      is a genuine positive byte delta between refreshes.


      NOTES

      • /tmp/sqstat_data.json is written on every refresh (tmpfs = RAM, no SSD writes)
      • Old closed connections remain in the JSON file but are ignored since
        they won't match any active Squid connection on the next poll
      • makeHtmlReport is not used by pfSense's version of SQStat (pfSense uses
        parseRequest + sqstat_resultHTML via AJAX) but was updated for consistency
      • Current speed requires at least 2 refreshes with the same connection
        active to show a value - this is expected behavior
      • Avg speed shows immediately on first load for connections > 1 second old
        ===============================
        End of change log

      Make sure to upvote

      1 Reply Last reply Reply Quote 0
      • First post
        Last post
      Copyright 2026 Rubicon Communications LLC (Netgate). All rights reserved.