OpsBloc Documentation

OpsBloc is a lightweight log forwarding and monitoring service that provides real-time insights into your application's performance and security. Send your application logs to OpsBloc and gain immediate visibility into request patterns, security threats, and performance bottlenecks.

What OpsBloc Does

Log Collection: Forward HTTP request logs from your application through a simple REST API.

Performance Monitoring: Track response times, identify slow endpoints, and monitor request patterns in real-time.

Security Analysis: Detect suspicious patterns including SQL injection attempts, XSS attacks, path traversal, command injection, and unusual traffic spikes.

Log Search: Quickly investigate performance or security issues with powerful search and filtering capabilities.

Real-time Alerting: Configure metric thresholds and receive notifications via webhooks or email when anomalies occur.

Getting Started

Installation Methods

You can send web logs to OpsBloc from three different levels of your stack: the web server, your programming language runtime, or your web framework. Each approach has its advantages, and you're welcome to choose what works best for your setup.

πŸ’» Language Runtime Level (JavaScript, Python, PHP, Ruby, etc.)

Pros: Portable across frameworks, good balance of control and simplicity, access to runtime-specific data.

Cons: Requires code changes in your application, needs to be implemented carefully to avoid blocking requests.

πŸ”§ Web Server Level (NGINX, Apache)

Pros: Captures all requests regardless of application code, easy to set up once, minimal performance impact, works across all apps on the server.

Cons: Less visibility into application-specific data like user IDs or custom metrics, requires server-level access.

πŸš€ Framework Level (Express, Django, Laravel, Rails, etc.)

Pros: Deep integration with your application, easy access to user sessions, custom context, and business logic, framework-specific optimizations.

Cons: Framework-specific implementation, might need updates when upgrading frameworks.

Note: We've done our best to test these integrations, but every production environment is unique. If you discover better implementations or notice any issues, we'd really appreciate your feedback! Feel free to reach out – we're always looking to improve.

Language Runtimes

To start sending logs to OpsBloc, you'll need an APP_ID and APP_TOKEN from your OpsBloc dashboard. The following examples demonstrate how to forward logs from various languages.

cURL

The simplest way to test log forwarding is using cURL. This example sends a single log entry to OpsBloc:


  curl -X POST "https://opsbloc.com/logs/APP_ID" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer APP_TOKEN" \
    -d '{
      "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
      "request_method": "POST",
      "request_url": "/api/login",
      "status": 200,
      "client_ip": "192.168.1.100",
      "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
      "request_time": 0.125,
      "request_body": "{\"email\":\"admin'\'OR 1=1--\"}",
      "referer": "https://example.com/login",
      "request_id": "uuid-1234",
      "user": "user123"
    }'

              

JavaScript

In vanilla JavaScript, use the Fetch API to send logs asynchronously without blocking your application:


  async function sendLog(logData) {
    try {
      await fetch('https://opsbloc.com/logs/APP_ID', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer APP_TOKEN'
        },
        body: JSON.stringify({
          timestamp: new Date().toISOString(),
          request_method: logData.method,
          request_url: logData.url,
          status: logData.status,
          client_ip: logData.ip,
          user_agent: navigator.userAgent,
          request_time: logData.responseTime,
          request_body: logData.body,
          referer: document.referrer,
          request_id: logData.requestId,
          user: logData.userId
        })
      });
    } catch (error) {
      console.error('Failed to send log:', error);
    }
  }

  // Usage
  sendLog({
    method: 'POST',
    url: '/api/login',
    status: 200,
    ip: '192.168.1.100',
    responseTime: 0.125,
    body: '{"email":"[email protected]"}',
    requestId: 'uuid-1234',
    userId: 'user123'
  });

              

Python

Using Python's requests library, send logs with proper error handling:


  import requests
  from datetime import datetime

  def send_log(log_data):
      url = "https://opsbloc.com/logs/APP_ID"
      headers = {
          "Content-Type": "application/json",
          "Authorization": "Bearer APP_TOKEN"
      }
      payload = {
          "timestamp": datetime.utcnow().isoformat() + "Z",
          "request_method": log_data["method"],
          "request_url": log_data["url"],
          "status": log_data["status"],
          "client_ip": log_data["ip"],
          "user_agent": log_data["user_agent"],
          "request_time": log_data["response_time"],
          "request_body": log_data.get("body", ""),
          "referer": log_data.get("referer", ""),
          "request_id": log_data.get("request_id", ""),
          "user": log_data.get("user", "")
      }
      
      try:
          requests.post(url, json=payload, headers=headers, timeout=5)
      except requests.exceptions.RequestException as e:
          print(f"Failed to send log: {e}")

  # Usage
  send_log({
      "method": "POST",
      "url": "/api/login",
      "status": 200,
      "ip": "192.168.1.100",
      "user_agent": "Mozilla/5.0",
      "response_time": 0.125,
      "body": '{"email":"[email protected]"}',
      "request_id": "uuid-1234",
      "user": "user123"
  })

              

PHP

In PHP, use cURL to send logs with minimal overhead:


  function sendLog($logData) {
      $url = "https://opsbloc.com/logs/APP_ID";
      $headers = [
          "Content-Type: application/json",
          "Authorization: Bearer APP_TOKEN"
      ];
      
      $payload = json_encode([
          "timestamp" => gmdate('Y-m-d\TH:i:s\Z'),
          "request_method" => $logData["method"],
          "request_url" => $logData["url"],
          "status" => $logData["status"],
          "client_ip" => $logData["ip"],
          "user_agent" => $logData["user_agent"],
          "request_time" => $logData["response_time"],
          "request_body" => $logData["body"] ?? "",
          "referer" => $logData["referer"] ?? "",
          "request_id" => $logData["request_id"] ?? "",
          "user" => $logData["user"] ?? ""
      ]);
      
      $ch = curl_init($url);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_TIMEOUT, 5);
      
      $result = curl_exec($ch);
      if (curl_errno($ch)) {
          error_log("Failed to send log: " . curl_error($ch));
      }
      curl_close($ch);
  }

  // Usage
  sendLog([
      "method" => "POST",
      "url" => "/api/login",
      "status" => 200,
      "ip" => $_SERVER['REMOTE_ADDR'],
      "user_agent" => $_SERVER['HTTP_USER_AGENT'],
      "response_time" => 0.125,
      "body" => file_get_contents('php://input'),
      "request_id" => uniqid(),
      "user" => "user123"
  ]);

              

Ruby

Use Ruby's net/http library to forward logs:


  require 'net/http'
  require 'json'
  require 'uri'

  def send_log(log_data)
    uri = URI('https://opsbloc.com/logs/APP_ID')
    http = Net::HTTP.new(uri.host, uri.port)
    http.open_timeout = 5
    http.read_timeout = 5
    
    request = Net::HTTP::Post.new(uri.path)
    request['Content-Type'] = 'application/json'
    request['Authorization'] = 'Bearer APP_TOKEN'
    request.body = {
      timestamp: Time.now.utc.iso8601,
      request_method: log_data[:method],
      request_url: log_data[:url],
      status: log_data[:status],
      client_ip: log_data[:ip],
      user_agent: log_data[:user_agent],
      request_time: log_data[:response_time],
      request_body: log_data[:body] || '',
      referer: log_data[:referer] || '',
      request_id: log_data[:request_id] || '',
      user: log_data[:user] || ''
    }.to_json
    
    begin
      http.request(request)
    rescue StandardError => e
      warn "Failed to send log: #{e.message}"
    end
  end

  # Usage
  send_log({
    method: 'POST',
    url: '/api/login',
    status: 200,
    ip: '192.168.1.100',
    user_agent: 'Mozilla/5.0',
    response_time: 0.125,
    body: '{"email":"[email protected]"}',
    request_id: SecureRandom.uuid,
    user: 'user123'
  })

              

Java

Using Java's HttpClient (Java 11+), send logs asynchronously:


  import java.net.http.*;
  import java.net.URI;
  import java.time.Instant;
  import org.json.JSONObject;

  public class OpsBlocLogger {
      private static final HttpClient client = HttpClient.newHttpClient();
      private static final String APP_ID = "APP_ID";
      private static final String APP_TOKEN = "APP_TOKEN";
      
      public static void sendLog(LogData logData) {
          JSONObject payload = new JSONObject();
          payload.put("timestamp", Instant.now().toString());
          payload.put("request_method", logData.method);
          payload.put("request_url", logData.url);
          payload.put("status", logData.status);
          payload.put("client_ip", logData.ip);
          payload.put("user_agent", logData.userAgent);
          payload.put("request_time", logData.responseTime);
          payload.put("request_body", logData.body);
          payload.put("referer", logData.referer);
          payload.put("request_id", logData.requestId);
          payload.put("user", logData.user);
          
          HttpRequest request = HttpRequest.newBuilder()
              .uri(URI.create("https://opsbloc.com/logs/" + APP_ID))
              .header("Content-Type", "application/json")
              .header("Authorization", "Bearer " + APP_TOKEN)
              .POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
              .timeout(java.time.Duration.ofSeconds(5))
              .build();
          
          client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
              .exceptionally(e -> {
                  System.err.println("Failed to send log: " + e.getMessage());
                  return null;
              });
      }
  }

              

Go

In Go, use the standard net/http package with a timeout context:


  package main

  import (
      "bytes"
      "context"
      "encoding/json"
      "net/http"
      "time"
  )

  type LogData struct {
      Timestamp     string  `json:"timestamp"`
      RequestMethod string  `json:"request_method"`
      RequestURL    string  `json:"request_url"`
      Status        int     `json:"status"`
      ClientIP      string  `json:"client_ip"`
      UserAgent     string  `json:"user_agent"`
      RequestTime   float64 `json:"request_time"`
      RequestBody   string  `json:"request_body,omitempty"`
      Referer       string  `json:"referer,omitempty"`
      RequestID     string  `json:"request_id,omitempty"`
      User          string  `json:"user,omitempty"`
  }

  func sendLog(logData LogData) error {
      logData.Timestamp = time.Now().UTC().Format(time.RFC3339)
      
      payload, _ := json.Marshal(logData)
      ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
      defer cancel()
      
      req, _ := http.NewRequestWithContext(ctx, "POST",
          "https://opsbloc.com/logs/APP_ID", bytes.NewBuffer(payload))
      req.Header.Set("Content-Type", "application/json")
      req.Header.Set("Authorization", "Bearer APP_TOKEN")
      
      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
          return err
      }
      defer resp.Body.Close()
      return nil
  }

              

Elixir

Using Elixir's HTTPoison library, send logs asynchronously:


  defmodule OpsBlocLogger do
    @app_id "APP_ID"
    @app_token "APP_TOKEN"
    @base_url "https://opsbloc.com/logs"

    def send_log(log_data) do
      url = "#{@base_url}/#{@app_id}"
      headers = [
        {"Content-Type", "application/json"},
        {"Authorization", "Bearer #{@app_token}"}
      ]
      
      payload = %{
        timestamp: DateTime.utc_now() |> DateTime.to_iso8601(),
        request_method: log_data.method,
        request_url: log_data.url,
        status: log_data.status,
        client_ip: log_data.ip,
        user_agent: log_data.user_agent,
        request_time: log_data.response_time,
        request_body: log_data[:body] || "",
        referer: log_data[:referer] || "",
        request_id: log_data[:request_id] || "",
        user: log_data[:user] || ""
      }
      
      case HTTPoison.post(url, Jason.encode!(payload), headers, recv_timeout: 5000) do
        {:ok, _response} -> :ok
        {:error, reason} -> 
          IO.puts("Failed to send log: #{inspect(reason)}")
          :error
      end
    end
  end

              

Web Servers

Configure your web server to forward logs to OpsBloc without impacting request performance. Both NGINX and Apache implementations use asynchronous logging to ensure your application responses remain fast.

NGINX

Configure NGINX to send logs to OpsBloc asynchronously without blocking request processing. This method uses the post_action directive to forward logs after the response is sent to the client.


  # /etc/nginx/nginx.conf or your site config

  http {
      # Define log format with all necessary fields
      log_format opsbloc_json escape=json '{'
          '"timestamp":"$time_iso8601",'
          '"request_method":"$request_method",'
          '"request_url":"$request_uri",'
          '"status":$status,'
          '"client_ip":"$remote_addr",'
          '"user_agent":"$http_user_agent",'
          '"request_time":$request_time,'
          '"referer":"$http_referer",'
          '"request_id":"$request_id"'
      '}';

      server {
          listen 80;
          server_name yourdomain.com;

          location / {
              # Your normal configuration
              proxy_pass http://your_backend;
              
              # Send log to OpsBloc after response (non-blocking)
              post_action @log_to_opsbloc;
          }

          # Internal location for logging
          location @log_to_opsbloc {
              internal;
              
              proxy_pass https://opsbloc.com/logs/APP_ID;
              proxy_method POST;
              proxy_set_header Content-Type application/json;
              proxy_set_header Authorization "Bearer APP_TOKEN";
              proxy_set_body $opsbloc_json_log;
              
              # Don't wait for response
              proxy_ignore_client_abort on;
              access_log off;
          }
      }
  }

              

Important: The post_action runs after the response is sent to the client, ensuring zero impact on response times. Replace APP_ID and APP_TOKEN with your actual credentials.

Advanced: If you need to capture request bodies or have OpenResty/lua-nginx-module installed, you can use log_by_lua_block for more flexibility. This requires additional setup but provides deeper integration. Contact us for Lua-based examples.

Apache

Configure Apache to send logs to OpsBloc using a custom log format and a simple script that processes logs asynchronously in the background.


  # Apache configuration
  # /etc/apache2/sites-available/yourdomain.conf

  <VirtualHost *:80>
      ServerName yourdomain.com

      # Define custom log format for OpsBloc
      LogFormat "{ \
        \"timestamp\":\"%{%Y-%m-%dT%H:%M:%S}t%{%z}t\", \
        \"request_method\":\"%m\", \
        \"request_url\":\"%U%q\", \
        \"status\":REPLACE_WITH_GT_s, \
        \"client_ip\":\"%a\", \
        \"user_agent\":\"%{User-agent}i\", \
        \"request_time\":%D, \
        \"referer\":\"%{Referer}i\", \
        \"request_id\":\"%{UNIQUE_ID}e\" \
      }" opsbloc_json

      # Pipe logs to a script that sends them asynchronously
      CustomLog "|$/usr/local/bin/opsbloc_logger.sh" opsbloc_json

      # Your normal configuration
      DocumentRoot /var/www/html
  </VirtualHost>

              

Use %>s instead of REPLACE_WITH_GT_s

Create the async logger script at /usr/local/bin/opsbloc_logger.sh:


  #!/bin/bash
  # /usr/local/bin/opsbloc_logger.sh

  APP_ID="YOUR_APP_ID"
  APP_TOKEN="YOUR_APP_TOKEN"

  while read line; do
      # Send to OpsBloc in background (non-blocking)
      (
          curl -X POST "https://opsbloc.com/logs/$APP_ID" \
              -H "Content-Type: application/json" \
              -H "Authorization: Bearer $APP_TOKEN" \
              -d "$line" \
              --max-time 5 \
              --silent \
              --show-error \
              > /dev/null 2>&1
      ) &
  done

              

Make the script executable: chmod +x /usr/local/bin/opsbloc_logger.sh. The script runs each curl request in the background, ensuring Apache doesn't wait for OpsBloc responses.

Advanced: If you have mod_lua enabled and need request body capture, a Lua-based solution using LuaHookLog can provide better performance. Contact us for Lua-based examples.

Framework Integration

These framework integrations are designed to minimize performance impact, handle OpsBloc downtime gracefully, and automatically capture request metadata. All implementations use asynchronous logging and include error handling to prevent crashes.

Node.js

Create a non-blocking logger module that queues logs and sends them in the background:


  // opsbloc-logger.js
  const https = require('https');

  class OpsBlocLogger {
    constructor(appId, appToken) {
      this.appId = appId;
      this.appToken = appToken;
      this.queue = [];
      this.processing = false;
    }

    log(req, res, responseTime) {
      const logData = {
        timestamp: new Date().toISOString(),
        request_method: req.method,
        request_url: req.url,
        status: res.statusCode,
        client_ip: req.ip || req.connection.remoteAddress,
        user_agent: req.headers['user-agent'],
        request_time: responseTime,
        request_body: req.body ? JSON.stringify(req.body) : '',
        referer: req.headers.referer || '',
        request_id: req.id || '',
        user: req.user?.id || ''
      };

      this.queue.push(logData);
      if (!this.processing) this.processQueue();
    }

    async processQueue() {
      if (this.queue.length === 0) {
        this.processing = false;
        return;
      }
      this.processing = true;
      const log = this.queue.shift();
      
      try {
        await this.sendLog(log);
      } catch (error) {
        console.error('OpsBloc logging failed:', error.message);
      }
      setImmediate(() => this.processQueue());
    }

    sendLog(logData) {
      return new Promise((resolve, reject) => {
        const data = JSON.stringify(logData);
        const options = {
          hostname: 'localhost',
          port: 4000,
          path: `/logs/${this.appId}`,
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.appToken}`,
            'Content-Length': data.length
          },
          timeout: 5000
        };

        const req = https.request(options, (res) => {
          res.on('data', () => {});
          res.on('end', () => resolve());
        });

        req.on('error', reject);
        req.on('timeout', () => {
          req.destroy();
          reject(new Error('Request timeout'));
        });

        req.write(data);
        req.end();
      });
    }
  }

  module.exports = new OpsBlocLogger('APP_ID', 'APP_TOKEN');

              

Next.js

Implement a Next.js middleware that logs all requests without blocking responses:


  // middleware.js
  import { NextResponse } from 'next/server';

  const APP_ID = 'APP_ID';
  const APP_TOKEN = 'APP_TOKEN';

  export async function middleware(request) {
    const startTime = Date.now();
    const response = NextResponse.next();
    
    // Log asynchronously after response
    response.waitUntil = (async () => {
      try {
        const responseTime = (Date.now() - startTime) / 1000;
        
        await fetch(`https://opsbloc.com/logs/${APP_ID}`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${APP_TOKEN}`
          },
          body: JSON.stringify({
            timestamp: new Date().toISOString(),
            request_method: request.method,
            request_url: request.nextUrl.pathname,
            status: response.status,
            client_ip: request.ip || request.headers.get('x-forwarded-for'),
            user_agent: request.headers.get('user-agent'),
            request_time: responseTime,
            referer: request.headers.get('referer'),
            request_id: crypto.randomUUID()
          }),
          signal: AbortSignal.timeout(5000)
        });
      } catch (error) {
        console.error('OpsBloc logging failed:', error);
      }
    })();
    
    return response;
  }

  export const config = {
    matcher: '/api/:path*'
  };

              

Express

Create an Express middleware that logs after the response is sent:


  // opsbloc-middleware.js
  const fetch = require('node-fetch');

  const APP_ID = 'APP_ID';
  const APP_TOKEN = 'APP_TOKEN';

  function opsBlocMiddleware(req, res, next) {
    const startTime = Date.now();
    const originalEnd = res.end;
    
    res.end = function(...args) {
      originalEnd.apply(res, args);
      
      const responseTime = (Date.now() - startTime) / 1000;
      fetch(`https://opsbloc.com/logs/${APP_ID}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${APP_TOKEN}`
        },
        body: JSON.stringify({
          timestamp: new Date().toISOString(),
          request_method: req.method,
          request_url: req.originalUrl,
          status: res.statusCode,
          client_ip: req.ip,
          user_agent: req.get('user-agent'),
          request_time: responseTime,
          request_body: JSON.stringify(req.body || {}),
          referer: req.get('referer'),
          request_id: req.id,
          user: req.user?.id
        }),
        timeout: 5000
      }).catch(error => {
        console.error('OpsBloc logging failed:', error.message);
      });
    };
    
    next();
  }

  module.exports = opsBlocMiddleware;

              

ASP.NET

Create an ASP.NET Core middleware that logs asynchronously using background tasks:


  // OpsBlocMiddleware.cs
  using System.Diagnostics;
  using System.Text;
  using System.Text.Json;

  public class OpsBlocMiddleware
  {
      private readonly RequestDelegate _next;
      private readonly HttpClient _httpClient;
      private const string AppId = "APP_ID";
      private const string AppToken = "APP_TOKEN";

      public OpsBlocMiddleware(RequestDelegate next, IHttpClientFactory httpClientFactory)
      {
          _next = next;
          _httpClient = httpClientFactory.CreateClient();
          _httpClient.Timeout = TimeSpan.FromSeconds(5);
      }

      public async Task InvokeAsync(HttpContext context)
      {
          var stopwatch = Stopwatch.StartNew();
          await _next(context);
          stopwatch.Stop();
          
          _ = Task.Run(async () =>
          {
              try
              {
                  var logData = new
                  {
                      timestamp = DateTime.UtcNow.ToString("o"),
                      request_method = context.Request.Method,
                      request_url = context.Request.Path.Value,
                      status = context.Response.StatusCode,
                      client_ip = context.Connection.RemoteIpAddress?.ToString(),
                      user_agent = context.Request.Headers["User-Agent"].ToString(),
                      request_time = stopwatch.Elapsed.TotalSeconds,
                      referer = context.Request.Headers["Referer"].ToString(),
                      request_id = context.TraceIdentifier,
                      user = context.User?.Identity?.Name
                  };

                  var json = JsonSerializer.Serialize(logData);
                  var content = new StringContent(json, Encoding.UTF8, "application/json");
                  
                  var request = new HttpRequestMessage(HttpMethod.Post,
                      $"https://opsbloc.com/logs/{AppId}");
                  request.Headers.Add("Authorization", $"Bearer {AppToken}");
                  request.Content = content;

                  await _httpClient.SendAsync(request);
              }
              catch (Exception ex)
              {
                  Console.WriteLine($"OpsBloc logging failed: {ex.Message}");
              }
          });
      }
  }

              

Flask

Use Flask's after_request hook with threading to log without blocking responses:


  from flask import Flask, request, g
  import requests
  import threading
  from datetime import datetime
  import time

  app = Flask(__name__)

  APP_ID = "APP_ID"
  APP_TOKEN = "APP_TOKEN"

  @app.before_request
  def before_request():
      g.start_time = time.time()

  @app.after_request
  def after_request(response):
      if hasattr(g, 'start_time'):
          response_time = time.time() - g.start_time
          thread = threading.Thread(
              target=send_log_async,
              args=(request, response, response_time)
          )
          thread.daemon = True
          thread.start()
      return response

  def send_log_async(request, response, response_time):
      try:
          log_data = {
              "timestamp": datetime.utcnow().isoformat() + "Z",
              "request_method": request.method,
              "request_url": request.path,
              "status": response.status_code,
              "client_ip": request.remote_addr,
              "user_agent": request.headers.get('User-Agent', ''),
              "request_time": response_time,
              "request_body": request.get_data(as_text=True),
              "referer": request.headers.get('Referer', ''),
              "request_id": request.headers.get('X-Request-ID', ''),
              "user": getattr(request, 'user_id', '')
          }
          
          requests.post(
              f"https://opsbloc.com/logs/{APP_ID}",
              json=log_data,
              headers={"Authorization": f"Bearer {APP_TOKEN}"},
              timeout=5
          )
      except Exception as e:
          app.logger.error(f"OpsBloc logging failed: {e}")

              

Django

Create a Django middleware that logs asynchronously using threads:


  # middleware/opsbloc_middleware.py
  import time
  import requests
  import threading
  from datetime import datetime

  APP_ID = "APP_ID"
  APP_TOKEN = "APP_TOKEN"

  class OpsBlocMiddleware:
      def __init__(self, get_response):
          self.get_response = get_response

      def __call__(self, request):
          start_time = time.time()
          response = self.get_response(request)
          response_time = time.time() - start_time
          
          thread = threading.Thread(
              target=self._send_log,
              args=(request, response, response_time)
          )
          thread.daemon = True
          thread.start()
          
          return response

      def _send_log(self, request, response, response_time):
          try:
              log_data = {
                  "timestamp": datetime.utcnow().isoformat() + "Z",
                  "request_method": request.method,
                  "request_url": request.path,
                  "status": response.status_code,
                  "client_ip": self._get_client_ip(request),
                  "user_agent": request.META.get('HTTP_USER_AGENT', ''),
                  "request_time": response_time,
                  "request_body": request.body.decode('utf-8') if request.body else '',
                  "referer": request.META.get('HTTP_REFERER', ''),
                  "request_id": request.META.get('HTTP_X_REQUEST_ID', ''),
                  "user": str(request.user.id) if request.user.is_authenticated else ''
              }
              
              requests.post(
                  f"https://opsbloc.com/logs/{APP_ID}",
                  json=log_data,
                  headers={"Authorization": f"Bearer {APP_TOKEN}"},
                  timeout=5
              )
          except Exception as e:
              print(f"OpsBloc logging failed: {e}")

      def _get_client_ip(self, request):
          x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
          if x_forwarded_for:
              return x_forwarded_for.split(',')[0]
          return request.META.get('REMOTE_ADDR')

              

WordPress

Add this code to your theme's functions.php or create a custom plugin:


  // functions.php or custom plugin
  define('OPSBLOC_APP_ID', 'APP_ID');
  define('OPSBLOC_APP_TOKEN', 'APP_TOKEN');

  add_action('shutdown', 'opsbloc_log_request');

  function opsbloc_log_request() {
      global $wp;
      
      $start_time = defined('REQUEST_START_TIME') ? REQUEST_START_TIME : microtime(true);
      $response_time = microtime(true) - $start_time;
      
      $log_data = array(
          'timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
          'request_method' => $_SERVER['REQUEST_METHOD'],
          'request_url' => home_url($wp->request),
          'status' => http_response_code(),
          'client_ip' => opsbloc_get_client_ip(),
          'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
          'request_time' => $response_time,
          'request_body' => file_get_contents('php://input'),
          'referer' => $_SERVER['HTTP_REFERER'] ?? '',
          'request_id' => uniqid(),
          'user' => get_current_user_id()
      );
      
      wp_remote_post('https://opsbloc.com/logs/' . OPSBLOC_APP_ID, array(
          'blocking' => false,
          'timeout' => 5,
          'headers' => array(
              'Content-Type' => 'application/json',
              'Authorization' => 'Bearer ' . OPSBLOC_APP_TOKEN
          ),
          'body' => json_encode($log_data)
      ));
  }

  function opsbloc_get_client_ip() {
      $ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');
      foreach ($ip_keys as $key) {
          if (isset($_SERVER[$key])) {
              $ip = explode(',', $_SERVER[$key]);
              return trim($ip[0]);
          }
      }
      return '';
  }

  define('REQUEST_START_TIME', microtime(true));

              

FastAPI

Use FastAPI's middleware with background tasks for non-blocking logging:


  from fastapi import FastAPI, Request
  import httpx
  import time
  from datetime import datetime

  app = FastAPI()

  APP_ID = "APP_ID"
  APP_TOKEN = "APP_TOKEN"

  @app.middleware("http")
  async def opsbloc_middleware(request: Request, call_next):
      start_time = time.time()
      response = await call_next(request)
      response_time = time.time() - start_time
      
      async def send_log():
          try:
              log_data = {
                  "timestamp": datetime.utcnow().isoformat() + "Z",
                  "request_method": request.method,
                  "request_url": str(request.url.path),
                  "status": response.status_code,
                  "client_ip": request.client.host,
                  "user_agent": request.headers.get("user-agent", ""),
                  "request_time": response_time,
                  "referer": request.headers.get("referer", ""),
                  "request_id": request.headers.get("x-request-id", ""),
                  "user": getattr(request.state, "user_id", "")
              }
              
              async with httpx.AsyncClient(timeout=5.0) as client:
                  await client.post(
                      f"https://opsbloc.com/logs/{APP_ID}",
                      json=log_data,
                      headers={"Authorization": f"Bearer {APP_TOKEN}"}
                  )
          except Exception as e:
              print(f"OpsBloc logging failed: {e}")
      
      import asyncio
      asyncio.create_task(send_log())
      
      return response

              

Laravel

Create a Laravel middleware that logs after the response using queued jobs:


  // app/Http/Middleware/OpsBlocMiddleware.php
  namespace App\Http\Middleware;

  use Closure;
  use Illuminate\Support\Facades\Http;
  use Illuminate\Http\Request;

  class OpsBlocMiddleware
  {
      public function handle(Request $request, Closure $next)
      {
          $startTime = microtime(true);
          $response = $next($request);
          $responseTime = microtime(true) - $startTime;
          
          app()->terminating(function () use ($request, $response, $responseTime) {
              $this->sendLog($request, $response, $responseTime);
          });
          
          return $response;
      }

      private function sendLog($request, $response, $responseTime)
      {
          try {
              $logData = [
                  'timestamp' => now()->toIso8601String(),
                  'request_method' => $request->method(),
                  'request_url' => $request->path(),
                  'status' => $response->status(),
                  'client_ip' => $request->ip(),
                  'user_agent' => $request->userAgent(),
                  'request_time' => $responseTime,
                  'request_body' => $request->getContent(),
                  'referer' => $request->header('referer', ''),
                  'request_id' => $request->header('x-request-id', ''),
                  'user' => optional($request->user())->id ?? ''
              ];

              Http::timeout(5)
                  ->withHeaders([
                      'Authorization' => 'Bearer ' . config('opsbloc.app_token')
                  ])
                  ->post(
                      'https://opsbloc.com/logs/' . config('opsbloc.app_id'),
                      $logData
                  );
          } catch (\Exception $e) {
              \Log::error('OpsBloc logging failed: ' . $e->getMessage());
          }
      }
  }

              

Rails

Create a Rails middleware that logs asynchronously using ActiveJob:


  # lib/middleware/ops_bloc_middleware.rb
  require 'net/http'
  require 'json'

  class OpsBlocMiddleware
    APP_ID = ENV['OPSBLOC_APP_ID'] || 'APP_ID'
    APP_TOKEN = ENV['OPSBLOC_APP_TOKEN'] || 'APP_TOKEN'

    def initialize(app)
      @app = app
    end

    def call(env)
      start_time = Time.now
      status, headers, response = @app.call(env)
      response_time = Time.now - start_time

      Thread.new do
        begin
          send_log(env, status, response_time)
        rescue StandardError => e
          Rails.logger.error "OpsBloc logging failed: #{e.message}"
        end
      end

      [status, headers, response]
    end

    private

    def send_log(env, status, response_time)
      request = ActionDispatch::Request.new(env)
      
      log_data = {
        timestamp: Time.now.utc.iso8601,
        request_method: request.request_method,
        request_url: request.fullpath,
        status: status,
        client_ip: request.remote_ip,
        user_agent: request.user_agent,
        request_time: response_time,
        request_body: request.body.read,
        referer: request.referer || '',
        request_id: request.request_id,
        user: request.env['warden']&.user&.id || ''
      }

      uri = URI("https://opsbloc.com/logs/#{APP_ID}")
      http = Net::HTTP.new(uri.host, uri.port)
      http.open_timeout = 5
      http.read_timeout = 5

      req = Net::HTTP::Post.new(uri.path)
      req['Content-Type'] = 'application/json'
      req['Authorization'] = "Bearer #{APP_TOKEN}"
      req.body = log_data.to_json

      http.request(req)
    end
  end

              

Symfony

Create a Symfony event subscriber that logs after the response is sent:


  // src/EventSubscriber/OpsBlocSubscriber.php
  namespace App\EventSubscriber;

  use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  use Symfony\Component\HttpKernel\Event\RequestEvent;
  use Symfony\Component\HttpKernel\Event\TerminateEvent;
  use Symfony\Component\HttpKernel\KernelEvents;
  use Symfony\Contracts\HttpClient\HttpClientInterface;

  class OpsBlocSubscriber implements EventSubscriberInterface
  {
      private $httpClient;
      private $startTime;
      private const APP_ID = 'APP_ID';
      private const APP_TOKEN = 'APP_TOKEN';

      public function __construct(HttpClientInterface $httpClient)
      {
          $this->httpClient = $httpClient;
      }

      public static function getSubscribedEvents()
      {
          return [
              KernelEvents::REQUEST => 'onKernelRequest',
              KernelEvents::TERMINATE => 'onKernelTerminate',
          ];
      }

      public function onKernelRequest(RequestEvent $event)
      {
          if (!$event->isMainRequest()) {
              return;
          }
          $this->startTime = microtime(true);
      }

      public function onKernelTerminate(TerminateEvent $event)
      {
          if (!$event->isMainRequest()) {
              return;
          }

          $responseTime = microtime(true) - $this->startTime;
          $request = $event->getRequest();
          $response = $event->getResponse();

          try {
              $logData = [
                  'timestamp' => (new \DateTime())->format(\DateTime::ATOM),
                  'request_method' => $request->getMethod(),
                  'request_url' => $request->getPathInfo(),
                  'status' => $response->getStatusCode(),
                  'client_ip' => $request->getClientIp(),
                  'user_agent' => $request->headers->get('User-Agent'),
                  'request_time' => $responseTime,
                  'request_body' => $request->getContent(),
                  'referer' => $request->headers->get('referer', ''),
                  'request_id' => $request->headers->get('X-Request-ID', ''),
                  'user' => $request->getUser() ?? ''
              ];

              $this->httpClient->request('POST',
                  'https://opsbloc.com/logs/' . self::APP_ID, [
                  'json' => $logData,
                  'headers' => [
                      'Authorization' => 'Bearer ' . self::APP_TOKEN
                  ],
                  'timeout' => 5
              ]);
          } catch (\Exception $e) {
              // Silently fail
          }
      }
  }

              

Guide

Settings & Timezone

Configure your application settings and timezone preferences in the OpsBloc dashboard. All timestamps in logs are stored in UTC and automatically converted to your selected timezone for display.

  • Application Settings: Manage your APP_ID and regenerate APP_TOKEN from the settings page
  • Timezone Configuration: Select your preferred timezone for log visualization and reports

Performance Monitoring

OpsBloc automatically analyzes request times and provides insights into your application's performance:

  • Response Time Tracking: View average, apdex, and 95th percentile response times
  • Slow Endpoint Detection: Identify endpoints that consistently perform poorly
  • Request Volume Analysis: Monitor request patterns and traffic spikes
  • Performance Trends: View historical performance data to identify degradation over time
  • Status Code Distribution: Track error rates and success ratios

Security Analysis

OpsBloc monitors your logs for suspicious patterns and potential security threats:

  • SQL Injection Detection: Identifies common SQL injection patterns in request bodies and URLs
  • XSS Attack Monitoring: Detects cross-site scripting attempts
  • Rate Limiting Violations: Identifies IPs making excessive requests
  • Path Traversal Detection: Identifies attempts to access files outside intended directories
  • Command Injection Monitoring: Detects shell command injection attempts in request parameters
  • Authentication Failures: Tracks failed login attempts and potential brute force attacks
  • Suspicious User Agents: Identifies known malicious bots and scanners

Alerting

Configure real-time alerts to be notified when specific conditions are met:

Alert Channels

  • Email Notifications: Receive alerts directly in your inbox
  • Webhooks: POST alert data to your own endpoints for custom integrations

Metric Thresholds

  • Error Rate: Alert when 4xx or 5xx responses exceed a threshold (e.g., >5% error rate)
  • Response Time: Notify when average response time exceeds configured limit (e.g., >2 seconds)
  • Request Volume: Alert on traffic spikes or unusual request patterns
  • Security Events: Immediate notification when potential attacks are detected
  • Alert Rules: Select alert rules using multiple metrics and set your thresholds

Alerts are sent immediately when thresholds are breached and include relevant context to help you investigate the issue quickly.

Support

Compliance & Privacy

What Data Does OpsBloc Collect?

When you forward logs to OpsBloc, we collect the following information to provide monitoring and security insights:

  • Request Metadata: HTTP method, URL path, status code, response time, and timestamp
  • Client Information: IP address, user agent, and referer
  • Request Body: POST/PUT request payloads (optional, can be disabled)
  • Custom Fields: User IDs, request IDs, or any additional metadata you choose to send

All data is stored securely with encryption at rest and in transit. You maintain full control over what data you send to OpsBloc through your integration configuration.

GDPR Compliance

OpsBloc is designed to be GDPR compliant. Under GDPR, OpsBloc operates as a Data Processor when handling log data on your behalf. Key compliance features include:

  • Data Control: You decide what personal data to send through your log configuration
  • Data Retention: Configure automatic log deletion after 7, 30, or 90 days based on your plan
  • Data Export: Export your logs as CSV at any time
  • Data Deletion: Delete individual logs or all logs for your application instantly
  • Right to Access: Full visibility into all data stored through your dashboard

To minimize personal data collection, consider:

  • Omitting the request_body field from your logs
  • Using anonymized or hashed user identifiers instead of email addresses
  • Filtering sensitive URL parameters before sending logs

HIPAA Considerations

OpsBloc can be deployed in HIPAA-compliant environments with proper configuration. To ensure Protected Health Information (PHI) is not inadvertently logged:

  • Exclude Request Bodies: Do not send the request_body field if it may contain PHI
  • Sanitize URLs: Remove patient identifiers, medical record numbers, or other PHI from URL paths before logging
  • Use Generic Identifiers: Log with anonymized session IDs rather than patient-specific identifiers
  • Review Your Configuration: Audit your logging implementation to ensure no PHI is being transmitted

For questions about deploying OpsBloc in HIPAA-compliant environments, contact our team.

PDPA Compliance

OpsBloc complies with Singapore's Personal Data Protection Act (PDPA) and similar data protection regulations across Asia-Pacific. As a Data Intermediary under PDPA, we provide:

  • Purpose Limitation: Log data is used solely for monitoring, security analysis, and performance optimization
  • Consent and Control: You control what personal data is included in logs through your integration
  • Data Accuracy: Real-time log data ensures accuracy of monitoring information
  • Protection: Industry-standard encryption and access controls protect log data
  • Retention Limitation: Automatic deletion after 30 days
  • Access and Correction: Full access to view, export, or delete your data at any time
  • Data Breach Notification: We will notify you promptly of any security incidents affecting your data

For PDPA-specific inquiries or to request our Data Protection Policy, please contact our team.

Payment Security

All payment processing is handled by Stripe, a PCI Level 1 certified payment processor. OpsBloc does not store or have access to your credit card information. Stripe's infrastructure has been audited by independent PCI Qualified Security Assessors and maintains the highest level of certification in the payments industry.

Contact Us

We're here to help with any questions, feedback, or issues you may encounter. Our team typically responds within 24 hours.

Get in Touch

For support, feature requests, compliance questions, or general inquiries:

team@opsbloc.com

We value your privacy and will never share your email address with third parties.