> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Minutely probes

export const VersionRequirements = ({versions = []}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const boundaries = {
    upper: " or lower",
    exact: "",
    lower: " or higher"
  };
  const containerStyle = {
    marginTop: "0.5rem",
    marginBottom: "1.5rem"
  };
  const lineStyle = {
    display: "block",
    margin: "0 0 0.35rem 0",
    fontSize: "0.875rem",
    lineHeight: "1.4"
  };
  const pillBaseStyle = {
    display: "inline-block",
    padding: "0.1em 0.4em",
    borderRadius: "0.25rem",
    border: "1px solid",
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
    fontSize: "0.85em",
    fontWeight: 500
  };
  const pillColors = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#e9d5ff",
      color: "#9333ea"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#99f6e4",
      color: "#0d9488"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#bbf7d0",
      color: "#16a34a"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#bfdbfe",
      color: "#2563eb"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fecaca",
      color: "#dc2626"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fed7aa",
      color: "#ea580c"
    }
  };
  const defaultPillColor = {
    background: "#f4f4f5",
    borderColor: "#e4e4e7",
    color: "#52525b"
  };
  const getPillStyle = name => ({
    ...pillBaseStyle,
    ...pillColors[name] || defaultPillColor
  });
  const getBoundText = bound => {
    return boundaries[bound] || boundaries.lower;
  };
  return <div style={containerStyle}>
      {versions.map((v, i) => <p key={`${v.name}-${v.version}-${v.bound || "lower"}-${i}`} style={lineStyle}>
          This feature requires{" "}
          <code style={getPillStyle(v.name)}>{v.name}</code> version {v.version}
          {getBoundText(v.bound)}.
        </p>)}
    </div>;
};

<VersionRequirements
  versions={[
{ name: "AppSignal for Python", version: "1.2.0" }
]}
/>

Minutely probes are a mechanism to periodically send custom metrics to AppSignal. In minutely intervals from when the probe was first created, a user-defined function can be called in which you can capture metrics to send them to AppSignal. Minutely probe functions are ran asynchronously.

You can enable or disable minutely probes entirely with the [`enable_minutely_probes`](/python/configuration/options#option-enable_minutely_probes) config option.

## Registering probes

To track custom metrics from your application, you can add your own probes. To register a probe, you must call the `probes.register()` method with two arguments: a probe name, and a function to be called once every minute.

<CodeGroup>
  ```python Python theme={null}
  from appsignal import probes, set_gauge

  def set_database_size_gauge():
      set_gauge("database_size", 10)

  probes.register("database", set_database_size_gauge)
  ```
</CodeGroup>

To ensure all minutely probes are ran in a timely manner, it is important to avoid blocking for long periods inside a minutely probe function.

## Stateful probes

A probe function can keep state in between executions by accepting it as an argument and returning it. This is useful to keep track of how values change over time:

<CodeGroup>
  ```python Python theme={null}
  from appsignal import probes, set_gauge

  def set_user_signups_gauge(previous_user_count):
      current_user_count = User.objects.all().count()

      if previous_user_count is not None:
        set_gauge("user_signups", current_user_count - previous_user_count)

      return current_user_count

  probes.register("user_signups", set_user_signups_gauge)
  ```
</CodeGroup>

The first time the minutely probe is called, `None` will be passed as the argument. In successive invocations, the value returned by the previous invocation will be passed to it as an argument.
