module infix-syslog {
  yang-version 1.1;
  namespace "urn:infix:syslog:ns:yang:1.0";
  prefix infix-syslog;


  import ietf-inet-types {
    prefix inet;
    reference "RFC 6991: Common YANG Data Types";
  }
  import ietf-syslog {
    prefix syslog;
  }

  organization "KernelKit";
  contact      "kernelkit@googlegroups.com";
  description  "Infix augments and deviations to ietf-syslog, draft 32.";

  revision 2025-11-17 {
    description "Add hostname-filter support.";
    reference "internal";
  }

  revision 2024-07-19 {
    description "Initial revision, based on IETF syslog YANG draft 32.
                 The following changes have been made in this model:

                   - Add support for global file rotation settings
                   - Add support for acting as a remote server
                   - Add support for local facility names
                   - Add support for log format selection per action
                   - Disable TLS transport, not yet supported
                   - Disable facility override, not yet supported
                   - Removed 1 log file default
                   - Replaced default 'megabytes' unit with 'kilobytes'";
    reference "internal";
  }

  /*
   * Identities
   */

  identity rauc {
    base syslog:syslog-facility;
    description "Local facility for the RAUC firmware update subsystem, local0.";
  }

  identity container {
    base syslog:syslog-facility;
    description "Local facility reserved for Docker containers, local1.";
  }

  identity web {
    base syslog:syslog-facility;
    description "Local facility reserved for web server, local7.";
  }

  // Log format

  identity format-type {
    description "This identity is used as a base for all log formats.";
    reference "RFC 5424: The Syslog Protocol";
  }

  identity bsd {
    base format-type;
    description "Original BSD UNIX log format, default when sending remote.";
  }

  identity rfc3164 {
    base format-type;
    description "Default log format, except when sending remote.";
  }

  identity rfc5424 {
    base format-type;
    description "Latest format, better time granularity, structured data, etc.";
  }

  /*
   * Shared settings
   */

  grouping log-format {
    leaf log-format {
      description "Log format, one of: BSD*, RFC3164, or RFC5424.

                   BSD     : myproc[8710]: Kilroy was here.
                   RFC3164 : Aug 24 05:14:15 192.0.2.1 myproc[8710]: Kilroy was here.
                   RFC5424 : 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - Kilroy was here.

                   Please note, BSD format is only applicable to remote logging.";
      type identityref {
        base format-type;
      }
    }
  }

  /*
   * Data Nodes
   */

  augment "/syslog:syslog" {
    container file-rotation {
      description "Global configuration parameters for log file rotation.

                   By default the last 10 rotated files are kept.  From
                   the second rotation the files are gzipped.

                   Example: syslog -> syslog.0 -> syslog.1.gz ...";

      leaf number-of-files {
        type uint32;
        default 10;
        description "Maximum number of log files retained.";
      }

      leaf max-file-size {
        type uint32;
        default 1024;
        units "kilobytes";
        description "Maximum log file size (kiB), before rotation.";
      }
    }

    container server {
      description "Syslog server settings, acting as a remote server (sink)";

      leaf enabled {
        description "Control listen to incoming syslog messages, default: off.

                     When enabled, the server listen on port 514 on all interfaces.
                     Use the listen directive to limit this to one or more on any
                     given port, if needed.";
        type boolean;
        default false;
      }

      container listen {
        description "Limit listen to the given interfaces[:port].";
        choice listen {
          case udp {
            list udp {
              key "port";
              leaf address {
                description "Interface to listen on, default: any.";
                type inet:ip-address;
              }

              leaf port {
                description "The Internet port to listen on, default: 514.";
                type inet:port-number;
                default 514;
              }
            }
          }
        }
      }
    }
  }

  augment "/syslog:syslog/syslog:actions/syslog:file/syslog:log-file" {
    description "Configurable log format for file logging.";
    uses log-format {
      refine log-format {
        default rfc3164;
        must "not(../log-format = 'infix-syslog:bsd')" {
          error-message "BSD log format is not applicable to file logging, only remote.";
        }
      }
    }

    leaf-list hostname-filter {
      type inet:domain-name;
      description "Filter messages by hostname. Messages from the listed
                   hostnames will be logged to this file.";
    }

    container property-filter {
      presence "Enable property-based filtering";
      description "Advanced property-based message filtering. Allows filtering
                   on specific message fields with various comparison operators.";

      leaf property {
        type enumeration {
          enum msg {
            description "The message body (SYSLOG-MSG field).";
          }
          enum msgid {
            description "The RFC5424 message identifier (MSGID field).";
          }
          enum programname {
            description "The originating program or tag name.";
          }
          enum hostname {
            description "The message source hostname.";
          }
          enum source {
            description "The message source (alias for hostname).";
          }
          enum data {
            description "The RFC5424 structured data (SD field).";
          }
        }
        mandatory true;
        description "The message property to match against.";
      }

      leaf operator {
        type enumeration {
          enum contains {
            description "Substring match (case-sensitive).";
          }
          enum isequal {
            description "Exact equality match.";
          }
          enum startswith {
            description "Prefix match.";
          }
          enum regex {
            description "Basic regular expression match.";
          }
          enum ereregex {
            description "Extended regular expression match (POSIX ERE).";
          }
        }
        mandatory true;
        description "The comparison operator to use.";
      }

      leaf value {
        type string;
        mandatory true;
        description "The value to compare against.";
      }

      leaf case-insensitive {
        type boolean;
        description "Perform case-insensitive comparison.";
      }

      leaf negate {
        type boolean;
        description "Negate the comparison result. When set to true, the
                     filter matches messages that do NOT satisfy the
                     specified condition.

                     For example:
                     - operator: contains, value: 'ERROR', negate: false
                       → matches messages containing 'ERROR'
                     - operator: contains, value: 'ERROR', negate: true
                       → matches messages NOT containing 'ERROR'";
      }
    }
  }

  augment "/syslog:syslog/syslog:actions/syslog:remote/syslog:destination" {
    description "Configurable log format for remote logging.";
    uses log-format {
      refine log-format {
        default bsd;
      }
    }
  }

  deviation "/syslog:syslog/syslog:actions/syslog:file/syslog:log-file/syslog:file-rotation/syslog:number-of-files" {
    description "Drop default 1 log file, defaults are handled by global file-rotation settings.";
    deviate delete {
      default 1;
    }
  }
  deviation "/syslog:syslog/syslog:actions/syslog:file/syslog:log-file/syslog:file-rotation/syslog:max-file-size" {
    description "Replace default 'megabytes' unit with 'kilobytes' to allow for better control.";
    deviate replace {
      type uint32;
      units "kilobytes";
    }
  }

  deviation "/syslog:syslog/syslog:actions/syslog:remote/syslog:destination/syslog:transport/syslog:tls" {
    description "Not yet supported by underlying daemon.";
    deviate not-supported;
  }
  deviation "/syslog:syslog/syslog:actions/syslog:remote/syslog:destination/syslog:facility-override" {
    description "Not yet supported by underlying daemon.";
    deviate not-supported;
  }
}
