# 7.2.4.2. Configuration / fichiers utiles

Se reporter au DIN, qui configure le cluster ElasticSearch de la chaîne de log.

Les fichiers de configuration sont définis sous `/vitam/conf/elasticsearch-log`.

## 7.2.4.2.1. Fichier `/vitam/conf/elasticsearch-log/log4j2.properties`

    status = error

    # log action execution errors for easier debugging
    logger.action.name = org.elasticsearch.action
    logger.action.level = {{ composant.action_log_level }}

    appender.console.type = Console
    appender.console.name = console
    appender.console.layout.type = PatternLayout
    appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%consoleException%n

    {% if syslog.name in ["rsyslog", "syslog-ng"] and (external_siem is defined or groups['hosts_logstash']|length > 0) %}
    appender.syslog.type = Syslog
    appender.syslog.name = syslog
    appender.syslog.appName = {{ composant.cluster_name }}
    appender.syslog.facility = {{ vitam_defaults.syslog_facility }}
    appender.syslog.host = {{ inventory_hostname }}
    appender.syslog.protocol = UDP
    appender.syslog.port = 514
    appender.syslog.layout.type = PatternLayout
    # Note: rsyslog only parse RFC3195-formatted syslog messages by default ; AND, to make it work with log4j2, we need to start the layout by the app-name.
    # IF we were in 5424, we wouldn't have to do this.
    appender.syslog.layout.pattern = {{ composant.cluster_name }}: [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker%m%n
    # appender.syslog.format = RFC5424
    # appender.syslog.mdcId = esdata

    rootLogger.appenderRef.syslog.ref = syslog
    {% else %}
    # Disabling the Syslog Appender
    # By setting `appender.syslog.type = Null`, this appender becomes inactive:
    # - No logs are sent to a Syslog daemon (e.g., rsyslog on 514/UDP).
    # - Prevents errors (e.g., AccessControlException) if rsyslog is not installed or configured.
    # - Logs are redirected to another active appender, here `console`, to be captured by Filebeat.
    # Used as a fallback when rsyslog is not present on the system.
    appender.syslog.type = Null
    appender.syslog.name = syslog
    rootLogger.appenderRef.console.ref = console
    {% endif %}

    appender.rolling.type = RollingFile
    appender.rolling.name = rolling
    appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log
    appender.rolling.layout.type = PatternLayout
    appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
    appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-%i.log.gz
    appender.rolling.policies.type = Policies
    appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
    appender.rolling.policies.time.interval = 1
    appender.rolling.policies.time.modulate = true
    appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
    appender.rolling.policies.size.size = {{ composant.log_appenders.rolling.max_log_file_size | default('10MB') }}
    appender.rolling.strategy.type = DefaultRolloverStrategy
    appender.rolling.strategy.fileIndex = {{ composant.log_appenders.rolling.fileIndex | default('nomax') }}
    appender.rolling.strategy.action.type = Delete
    appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path}
    appender.rolling.strategy.action.condition.type = IfFileName
    appender.rolling.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-*
    appender.rolling.strategy.action.condition.nested_condition.type = {{ composant.log_appenders.rolling.condition_type | default('IfAccumulatedFileSize') }}
    appender.rolling.strategy.action.condition.nested_condition.exceeds = {{ composant.log_appenders.rolling.max_total_log_size | default('5GB') }}

    rootLogger.level = {{ composant.log_appenders.root.log_level | default('info') }}
    rootLogger.appenderRef.console.ref = console
    rootLogger.appenderRef.rolling.ref = rolling

    appender.deprecation_rolling.type = RollingFile
    appender.deprecation_rolling.name = deprecation_rolling
    appender.deprecation_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_deprecation.log
    appender.deprecation_rolling.layout.type = PatternLayout
    appender.deprecation_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %.-10000m%n
    appender.deprecation_rolling.filter.rate_limit.type = RateLimitingFilter
    appender.deprecation_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_deprecation-%i.log.gz
    appender.deprecation_rolling.policies.type = Policies
    appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy
    appender.deprecation_rolling.policies.size.size = {{ composant.log_appenders.deprecation_rolling.max_log_file_size | default('10MB') }}
    appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy
    appender.deprecation_rolling.strategy.max = {{ composant.log_appenders.deprecation_rolling.max_files | default('10') }}

    appender.header_warning.type = HeaderWarningAppender
    appender.header_warning.name = header_warning

    logger.deprecation.name = org.elasticsearch.deprecation
    logger.deprecation.level = {{ composant.log_appenders.deprecation_rolling.log_level | default('warn') }}
    logger.deprecation.appenderRef.deprecation_rolling.ref = deprecation_rolling
    logger.deprecation.appenderRef.header_warning.ref = header_warning
    logger.deprecation.additivity = false

    appender.index_search_slowlog_rolling.type = RollingFile
    appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling
    appender.index_search_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog.log
    appender.index_search_slowlog_rolling.layout.type = PatternLayout
    appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] [%node_name]%marker %.-10000m%n
    appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog-%d{yyyy-MM-dd}.log.gz
    appender.index_search_slowlog_rolling.policies.type = Policies
    appender.index_search_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy
    appender.index_search_slowlog_rolling.policies.time.interval = 1
    appender.index_search_slowlog_rolling.policies.time.modulate = true

    logger.index_search_slowlog_rolling.name = index.search.slowlog
    logger.index_search_slowlog_rolling.level = {{ composant.log_appenders.index_search_slowlog_rolling.log_level | default('warn') }}
    logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling.ref = index_search_slowlog_rolling
    logger.index_search_slowlog_rolling.additivity = false

    appender.index_indexing_slowlog_rolling.type = RollingFile
    appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling
    appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog.log
    appender.index_indexing_slowlog_rolling.layout.type = PatternLayout
    appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] [%node_name]%marker %.-10000m%n
    appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog-%d{yyyy-MM-dd}.log.gz
    appender.index_indexing_slowlog_rolling.policies.type = Policies
    appender.index_indexing_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy
    appender.index_indexing_slowlog_rolling.policies.time.interval = 1
    appender.index_indexing_slowlog_rolling.policies.time.modulate = true

    logger.index_indexing_slowlog.name = index.indexing.slowlog.index
    logger.index_indexing_slowlog.level = {{ composant.log_appenders.index_indexing_slowlog_rolling.log_level | default('warn') }}
    logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling
    logger.index_indexing_slowlog.additivity = false

    logger.org_apache_pdfbox.name = org.apache.pdfbox
    logger.org_apache_pdfbox.level = off

    logger.org_apache_poi.name = org.apache.poi
    logger.org_apache_poi.level = off

    logger.org_apache_fontbox.name = org.apache.fontbox
    logger.org_apache_fontbox.level = off

    logger.org_apache_xmlbeans.name = org.apache.xmlbeans
    logger.org_apache_xmlbeans.level = off

    logger.com_amazonaws.name = com.amazonaws
    logger.com_amazonaws.level = warn

    logger.com_amazonaws_jmx_SdkMBeanRegistrySupport.name = com.amazonaws.jmx.SdkMBeanRegistrySupport
    logger.com_amazonaws_jmx_SdkMBeanRegistrySupport.level = error

    logger.com_amazonaws_metrics_AwsSdkMetrics.name = com.amazonaws.metrics.AwsSdkMetrics
    logger.com_amazonaws_metrics_AwsSdkMetrics.level = error

    logger.com_amazonaws_auth_profile_internal_BasicProfileConfigFileLoader.name = com.amazonaws.auth.profile.internal.BasicProfileConfigFileLoader
    logger.com_amazonaws_auth_profile_internal_BasicProfileConfigFileLoader.level = error

    logger.com_amazonaws_services_s3_internal_UseArnRegionResolver.name = com.amazonaws.services.s3.internal.UseArnRegionResolver
    logger.com_amazonaws_services_s3_internal_UseArnRegionResolver.level = error

    appender.audit_rolling.type = RollingFile
    appender.audit_rolling.name = audit_rolling
    appender.audit_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_audit.log
    appender.audit_rolling.layout.type = PatternLayout
    appender.audit_rolling.layout.pattern = {\
                    "type":"audit", \
                    "timestamp":"%d{yyyy-MM-dd'T'HH:mm:ss,SSSZ}"\
                    %varsNotEmpty{, "cluster.name":"%enc{\%map{cluster.name}}{JSON}"}\
                    %varsNotEmpty{, "cluster.uuid":"%enc{\%map{cluster.uuid}}{JSON}"}\
                    %varsNotEmpty{, "node.name":"%enc{\%map{node.name}}{JSON}"}\
                    %varsNotEmpty{, "node.id":"%enc{\%map{node.id}}{JSON}"}\
                    %varsNotEmpty{, "host.name":"%enc{\%map{host.name}}{JSON}"}\
                    %varsNotEmpty{, "host.ip":"%enc{\%map{host.ip}}{JSON}"}\
                    %varsNotEmpty{, "event.type":"%enc{\%map{event.type}}{JSON}"}\
                    %varsNotEmpty{, "event.action":"%enc{\%map{event.action}}{JSON}"}\
                    %varsNotEmpty{, "authentication.type":"%enc{\%map{authentication.type}}{JSON}"}\
                    %varsNotEmpty{, "user.name":"%enc{\%map{user.name}}{JSON}"}\
                    %varsNotEmpty{, "user.run_by.name":"%enc{\%map{user.run_by.name}}{JSON}"}\
                    %varsNotEmpty{, "user.run_as.name":"%enc{\%map{user.run_as.name}}{JSON}"}\
                    %varsNotEmpty{, "user.realm":"%enc{\%map{user.realm}}{JSON}"}\
                    %varsNotEmpty{, "user.realm_domain":"%enc{\%map{user.realm_domain}}{JSON}"}\
                    %varsNotEmpty{, "user.run_by.realm":"%enc{\%map{user.run_by.realm}}{JSON}"}\
                    %varsNotEmpty{, "user.run_by.realm_domain":"%enc{\%map{user.run_by.realm_domain}}{JSON}"}\
                    %varsNotEmpty{, "user.run_as.realm":"%enc{\%map{user.run_as.realm}}{JSON}"}\
                    %varsNotEmpty{, "user.run_as.realm_domain":"%enc{\%map{user.run_as.realm_domain}}{JSON}"}\
                    %varsNotEmpty{, "user.roles":%map{user.roles}}\
                    %varsNotEmpty{, "apikey.id":"%enc{\%map{apikey.id}}{JSON}"}\
                    %varsNotEmpty{, "apikey.name":"%enc{\%map{apikey.name}}{JSON}"}\
                    %varsNotEmpty{, "authentication.token.name":"%enc{\%map{authentication.token.name}}{JSON}"}\
                    %varsNotEmpty{, "authentication.token.type":"%enc{\%map{authentication.token.type}}{JSON}"}\
                    %varsNotEmpty{, "cross_cluster_access":%map{cross_cluster_access}}\
                    %varsNotEmpty{, "origin.type":"%enc{\%map{origin.type}}{JSON}"}\
                    %varsNotEmpty{, "origin.address":"%enc{\%map{origin.address}}{JSON}"}\
                    %varsNotEmpty{, "realm":"%enc{\%map{realm}}{JSON}"}\
                    %varsNotEmpty{, "realm_domain":"%enc{\%map{realm_domain}}{JSON}"}\
                    %varsNotEmpty{, "url.path":"%enc{\%map{url.path}}{JSON}"}\
                    %varsNotEmpty{, "url.query":"%enc{\%map{url.query}}{JSON}"}\
                    %varsNotEmpty{, "request.method":"%enc{\%map{request.method}}{JSON}"}\
                    %varsNotEmpty{, "request.body":"%enc{\%map{request.body}}{JSON}"}\
                    %varsNotEmpty{, "request.id":"%enc{\%map{request.id}}{JSON}"}\
                    %varsNotEmpty{, "action":"%enc{\%map{action}}{JSON}"}\
                    %varsNotEmpty{, "request.name":"%enc{\%map{request.name}}{JSON}"}\
                    %varsNotEmpty{, "indices":%map{indices}}\
                    %varsNotEmpty{, "opaque_id":"%enc{\%map{opaque_id}}{JSON}"}\
                    %varsNotEmpty{, "trace.id":"%enc{\%map{trace.id}}{JSON}"}\
                    %varsNotEmpty{, "x_forwarded_for":"%enc{\%map{x_forwarded_for}}{JSON}"}\
                    %varsNotEmpty{, "transport.profile":"%enc{\%map{transport.profile}}{JSON}"}\
                    %varsNotEmpty{, "rule":"%enc{\%map{rule}}{JSON}"}\
                    %varsNotEmpty{, "put":%map{put}}\
                    %varsNotEmpty{, "delete":%map{delete}}\
                    %varsNotEmpty{, "change":%map{change}}\
                    %varsNotEmpty{, "create":%map{create}}\
                    %varsNotEmpty{, "invalidate":%map{invalidate}}\
                    }%n
    # "node.name" node name from the `elasticsearch.yml` settings
    # "node.id" node id which should not change between cluster restarts
    # "host.name" unresolved hostname of the local node
    # "host.ip" the local bound ip (i.e. the ip listening for connections)
    # "origin.type" a received REST request is translated into one or more transport requests. This indicates which processing layer generated the event "rest" or "transport" (internal)
    # "event.action" the name of the audited event, eg. "authentication_failed", "access_granted", "run_as_granted", etc.
    # "authentication.type" one of "realm", "api_key", "token", "anonymous" or "internal"
    # "user.name" the subject name as authenticated by a realm
    # "user.run_by.name" the original authenticated subject name that is impersonating another one.
    # "user.run_as.name" if this "event.action" is of a run_as type, this is the subject name to be impersonated as.
    # "user.realm" the name of the realm that authenticated "user.name"
    # "user.realm_domain" if "user.realm" is under a domain, this is the name of the domain
    # "user.run_by.realm" the realm name of the impersonating subject ("user.run_by.name")
    # "user.run_by.realm_domain" if "user.run_by.realm" is under a domain, this is the name of the domain
    # "user.run_as.realm" if this "event.action" is of a run_as type, this is the realm name the impersonated user is looked up from
    # "user.run_as.realm_domain" if "user.run_as.realm" is under a domain, this is the name of the domain
    # "user.roles" the roles array of the user; these are the roles that are granting privileges
    # "apikey.id" this field is present if and only if the "authentication.type" is "api_key"
    # "apikey.name" this field is present if and only if the "authentication.type" is "api_key"
    # "authentication.token.name" this field is present if and only if the authenticating credential is a service account token
    # "authentication.token.type" this field is present if and only if the authenticating credential is a service account token
    # "cross_cluster_access" this field is present if and only if the associated authentication occurred cross cluster
    # "event.type" informs about what internal system generated the event; possible values are "rest", "transport", "ip_filter" and "security_config_change"
    # "origin.address" the remote address and port of the first network hop, i.e. a REST proxy or another cluster node
    # "realm" name of a realm that has generated an "authentication_failed" or an "authentication_successful"; the subject is not yet authenticated
    # "realm_domain" if "realm" is under a domain, this is the name of the domain
    # "url.path" the URI component between the port and the query string; it is percent (URL) encoded
    # "url.query" the URI component after the path and before the fragment; it is percent (URL) encoded
    # "request.method" the method of the HTTP request, i.e. one of GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, TRACE, CONNECT
    # "request.body" the content of the request body entity, JSON escaped
    # "request.id" a synthetic identifier for the incoming request, this is unique per incoming request, and consistent across all audit events generated by that request
    # "action" an action is the most granular operation that is authorized and this identifies it in a namespaced way (internal)
    # "request.name" if the event is in connection to a transport message this is the name of the request class, similar to how rest requests are identified by the url path (internal)
    # "indices" the array of indices that the "action" is acting upon
    # "opaque_id" opaque value conveyed by the "X-Opaque-Id" request header
    # "trace_id" an identifier conveyed by the part of "traceparent" request header
    # "x_forwarded_for" the addresses from the "X-Forwarded-For" request header, as a verbatim string value (not an array)
    # "transport.profile" name of the transport profile in case this is a "connection_granted" or "connection_denied" event
    # "rule" name of the applied rule if the "origin.type" is "ip_filter"
    # the "put", "delete", "change", "create", "invalidate" fields are only present
    # when the "event.type" is "security_config_change" and contain the security config change (as an object) taking effect

    appender.audit_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_audit-%d{yyyy-MM-dd}.log.gz
    appender.audit_rolling.policies.type = Policies
    appender.audit_rolling.policies.time.type = TimeBasedTriggeringPolicy
    appender.audit_rolling.policies.time.interval = 1
    appender.audit_rolling.policies.time.modulate = true

    logger.xpack_security_audit_logfile.name = org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail
    logger.xpack_security_audit_logfile.level = info
    logger.xpack_security_audit_logfile.appenderRef.audit_rolling.ref = audit_rolling
    logger.xpack_security_audit_logfile.additivity = false

    logger.xmlsig.name = org.apache.xml.security.signature.XMLSignature
    logger.xmlsig.level = error
    logger.samlxml_decrypt.name = org.opensaml.xmlsec.encryption.support.Decrypter
    logger.samlxml_decrypt.level = fatal
    logger.saml2_decrypt.name = org.opensaml.saml.saml2.encryption.Decrypter
    logger.saml2_decrypt.level = fatal

## 7.2.4.2.2. Fichier `/vitam/conf/elasticsearch-log/jvm.options`

    ## JVM configuration

    ################################################################
    ## IMPORTANT: JVM heap size
    ################################################################
    ##
    ## You should always set the min and max JVM heap
    ## size to the same value. For example, to set
    ## the heap to 4 GB, set:
    ##
    ## -Xms4g
    ## -Xmx4g
    ##
    ## See https://www.elastic.co/guide/en/elasticsearch/reference/current/heap-size.html
    ## for more information
    ##
    ################################################################

    # Xms represents the initial size of total heap space
    # Xmx represents the maximum size of total heap space

    -Xms{{ elasticsearch_memory }}
    -Xmx{{ elasticsearch_memory }}

    ################################################################
    ## Expert settings
    ################################################################
    ##
    ## All settings below this section are considered
    ## expert settings. Don't tamper with them unless
    ## you understand what you are doing
    ##
    ################################################################

    ## GC configuration
    8-13:-XX:+UseConcMarkSweepGC
    8-13:-XX:CMSInitiatingOccupancyFraction=75
    8-13:-XX:+UseCMSInitiatingOccupancyOnly

    ## G1GC Configuration
    # NOTE: G1 GC is only supported on JDK version 10 or later
    # to use G1GC, uncomment the next two lines and update the version on the
    # following three lines to your version of the JDK
    # 10-13:-XX:-UseConcMarkSweepGC
    # 10-13:-XX:-UseCMSInitiatingOccupancyOnly
    14-:-XX:+UseG1GC
    14-:-XX:G1ReservePercent=25
    14-:-XX:InitiatingHeapOccupancyPercent=30

    ## DNS cache policy
    # cache ttl in seconds for positive DNS lookups noting that this overrides the
    # JDK security property networkaddress.cache.ttl; set to -1 to cache forever
    -Des.networkaddress.cache.ttl=60
    # cache ttl in seconds for negative DNS lookups noting that this overrides the
    # JDK security property networkaddress.cache.negative ttl; set to -1 to cache
    # forever
    -Des.networkaddress.cache.negative.ttl=10

    ## optimizations

    # pre-touch memory pages used by the JVM during initialization
    -XX:+AlwaysPreTouch

    ## basic
    # force the server VM (remove on 32-bit client JVMs)
    -server

    # explicitly set the stack size
    -Xss1m

    # set to headless, just in case
    -Djava.awt.headless=true

    # ensure UTF-8 encoding by default (e.g. filenames)
    -Dfile.encoding=UTF-8

    # use our provided JNA always versus the system one
    -Djna.nosys=true

    # turn off a JDK optimization that throws away stack traces for common
    # exceptions because stack traces are important for debugging
    -XX:-OmitStackTraceInFastThrow

    # flags to configure Netty
    -Dio.netty.noUnsafe=true
    -Dio.netty.noKeySetOptimization=true
    -Dio.netty.recycler.maxCapacityPerThread=0

    # log4j 2
    -Dlog4j.shutdownHookEnabled=false
    -Dlog4j2.disable.jmx=true
    # Prevent from exploit in old log4j2 versions <2.17.1
    -Dlog4j2.formatMsgNoLookups=true

    -Dlog4j.skipJansi=true
    -Djava.io.tmpdir=${ES_TMPDIR}

    ## heap dumps

    # generate a heap dump when an allocation from the Java heap fails
    # heap dumps are created in the working directory of the JVM
    -XX:+HeapDumpOnOutOfMemoryError

    # specify an alternative path for heap dumps; ensure the directory exists and
    # has sufficient space
    -XX:HeapDumpPath={{ elasticsearch_log_dir }}

    # specify an alternative path for JVM fatal error logs
    -XX:ErrorFile={{ elasticsearch_log_dir }}/hs_err_pid%p.log

    ## JDK 8 GC logging

    8:-XX:+PrintGCDetails
    8:-XX:+PrintGCDateStamps
    8:-XX:+PrintTenuringDistribution
    8:-XX:+PrintGCApplicationStoppedTime
    8:-Xloggc:/var/log/elasticsearch/gc.log
    8:-XX:+UseGCLogFileRotation
    8:-XX:NumberOfGCLogFiles=8
    8:-XX:GCLogFileSize=32m

    # JDK 9+ GC logging
    9-:-Xlog:gc*,gc+age=trace,safepoint:file={{ elasticsearch_log_dir }}/gc.log:utctime,pid,tags:filecount=8,filesize=32m

    -Djna.tmpdir={{ vitam_defaults.folder.root_path }}/tmp/{{ composant.cluster_name }}

## 7.2.4.2.3. Fichier `/vitam/conf/elasticsearch-log/elasticsearch.yml`

    # ======================== Elasticsearch Configuration =========================
    #
    # NOTE: Elasticsearch comes with reasonable defaults for most settings.
    #       Before you set out to tweak and tune the configuration, make sure you
    #       understand what are you trying to accomplish and the consequences.
    #
    # The primary way of configuring a node is via this file. This template lists
    # the most important settings you may want to configure for a production cluster.
    #
    # Please consult the documentation for further information on configuration options:
    # https://www.elastic.co/guide/en/elasticsearch/reference/index.html
    #
    # ---------------------------------- Cluster -----------------------------------
    #
    # Use a descriptive name for your cluster:
    #
    cluster.name: {{ composant.cluster_name }}
    #
    # ------------------------------------ Node ------------------------------------
    #
    # Use a descriptive name for the node:
    #
    node.name: {{ inventory_hostname }}

    # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-node.html#node-roles
    # node.roles: [master, data, data_content, data_hot, data_warm, data_cold, data_frozen, ingest, ml, remote_cluster_client, transform]
    {% if groups['hosts_logstash'] | length > 0 %}
    node.roles: {{ elasticsearch_roles | default(['master', 'data']) }}
    {% else %}
    node.roles: {{ elasticsearch_roles | default(['master', 'data', 'ingest']) }}
    {% endif %}

    # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/ml-settings.html
    xpack.ml.enabled: false

    #
    # Add custom attributes to the node:
    #
    #node.attr.rack: r1
    #
    # ----------------------------------- Paths ------------------------------------
    #
    # Path to directory where to store the data (separate multiple locations by comma):
    #
    path.data: {{ elasticsearch_data_dir }}
    #
    # Path to log files:
    #
    path.logs: {{ elasticsearch_log_dir }}

    #
    # Path for backup/snapshots:
    #
    {% if (composant.repo is defined) and (composant.repo|length > 0) and ("" not in composant.repo) %}
    path.repo: ["{{ composant.repo | list | join ('\',\'') }}"]
    {% endif %}

    #
    # ----------------------------------- Memory -----------------------------------
    #
    # Lock the memory on startup:
    # = Disable swapping
    bootstrap.memory_lock: true
    #
    # Make sure that the heap size is set to about half the memory available
    # on the system and that the owner of the process is allowed to use this
    # limit.
    #
    # Elasticsearch performs poorly when the system is swapping the memory.
    #
    # ---------------------------------- Network -----------------------------------
    #
    # By default Elasticsearch is only accessible on localhost. Set a different
    # address here to expose this node on the network:
    #
    # Note : if installing to localhost, notably a docker container, we need to bind larger than localhost
    {% if inventory_hostname in single_vm_hostnames %}
    network.host: {{ composant.network_host | default('0.0.0.0') }}
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    {% else %}
    network.host: {{ ip_admin }}
    {% endif %}
    #
    # By default Elasticsearch listens for HTTP traffic on the first free port it
    # finds starting at 9200. Set a specific HTTP port here:
    #
    http.port: {{ composant.port_http }}
    #
    # For more information, consult the network module documentation.
    #
    # --------------------------------- Discovery ----------------------------------
    #
    # Pass an initial list of hosts to perform discovery when this node is started:
    # The default list of hosts is ["127.0.0.1", "[::1]"]
    #
    {% if groups['hosts_elasticsearch_log'] | length > 1 %}
    discovery.seed_hosts: [ {% for host in groups['hosts_elasticsearch_log'] %}"{{ hostvars[host]['ip_admin'] }}"{% if not loop.last %},{% endif %}{% endfor %} ]
    {% endif %}
    #
    # Bootstrap the cluster using an initial set of master-eligible nodes:
    #
    # TODO OMA : faire mieux, plus propre et prenant bien en compte is_master de chaque membre
    cluster.initial_master_nodes: [ {% for host in groups['hosts_elasticsearch_log'] %}"{{ hostvars[host]['ip_admin'] }}"{% if not loop.last %},{% endif %}{% endfor %} ]
    #
    # For more information, consult the discovery and cluster formation module documentation.
    #
    # ---------------------------------- Gateway -----------------------------------
    #
    # Block initial recovery after a full cluster restart until N nodes are started:
    #
    # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-gateway.html
    #gateway.recover_after_nodes: 3
    #
    # For more information, see the documentation at:
    # <http://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-gateway.html>
    #
    # ---------------------------------- Various -----------------------------------
    #
    # Allow wildcard deletion of indices:
    #
    action.destructive_requires_name: true

    indices.mapping.dynamic_timeout: {{ composant.dynamic_timeout |default('30s') }}

    # thread_pool configuration
    # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-threadpool.html
    thread_pool:
        analyze:
            size: {{ (ansible_processor_cores * ansible_processor_threads_per_core) | round (0, 'floor') | int }}
            queue_size: 5000
        get:
            size: {{ elasticsearch.log.thread_pool.get.size |default((ansible_processor_cores * ansible_processor_threads_per_core)| round (0, 'floor') | int) }}
            queue_size: 1000
        search:
            size: {{ elasticsearch.log.thread_pool.search.size |default(((ansible_processor_cores * ansible_processor_threads_per_core * 3 / 2) + 1) | round (0, 'floor') | int) }}
            queue_size: 1000
        write:
            size: {{ elasticsearch.log.thread_pool.write.size |default((ansible_processor_cores * ansible_processor_threads_per_core + 1)| round (0, 'floor') | int) }}
            queue_size: 5000
        warmer:
            core: 1
            max: {{ elasticsearch.log.thread_pool.warmer.max |default(((ansible_processor_cores * ansible_processor_threads_per_core / 2) + 0.5) | round (0, 'floor') | int) }}
            keep_alive: 2m

    # Note : the 0.5 in the previous expression is for there is only 1 CPU (else the thread pool size would be zero) ! ; Note bis : max 10 threads #
    # Note : in ES5 and further : the thread pool "refresh" is of type scaling with a keep-alive of 5m and a max of min(10, (# of available processors)/2)

    # related to https://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-fielddata.html
    indices.fielddata.cache.size: {{ composant.indices_fielddata_cache_size | default('30%') }}

    # related to https://www.elastic.co/guide/en/elasticsearch/reference/8.13/circuit-breaker.html#fielddata-circuit-breaker
    indices.breaker.fielddata.limit: {{ composant.indices_breaker_fielddata_limit | default('40%') }}

    {% if groups['hosts_elasticsearch_log']|length > 1 %}
    # related to affinity and balancing between racks / rooms
    # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/modules-cluster.html#shard-allocation-awareness
    cluster.routing.allocation.awareness.attributes: rack_id
    node.attr.rack_id: {{ is_balancing|default(vitam_site_name) }}
    {% endif %}

    indices.breaker.total.use_real_memory: false

    # Related to https://www.elastic.co/guide/en/elasticsearch/reference/8.13/ilm-settings.html
    indices.lifecycle.history_index_enabled: true

    #----------------------- BEGIN SECURITY CONFIGURATION -----------------------

    # Enable security features
    xpack.security.enabled: false

    # Disable watcher features (to send notifications)
    xpack.watcher.enabled: false

## 7.2.4.2.4. Fichier `/vitam/conf/elasticsearch-log/sysconfig`

    ################################
    # Elasticsearch
    ################################

    # Elasticsearch home directory
    #ES_HOME=/usr/share/elasticsearch

    # Elasticsearch configuration directory
    ES_PATH_CONF={{ vitam_defaults.folder.root_path }}/conf/{{ composant.cluster_name }}

    # Elasticsearch data directory
    #DATA_DIR={{ vitam_defaults.folder.root_path }}/data/{{ composant.cluster_name }}

    # Elasticsearch logs directory
    #LOG_DIR={{ vitam_defaults.folder.root_path }}/log/{{ composant.cluster_name }}

    # Elasticsearch PID directory
    #PID_DIR=/var/run/{{ composant.cluster_name }}

    # Heap size defaults to 256m min, 1g max
    # Set ES_HEAP_SIZE to 50% of available RAM, but no more than 31g
    #ES_JAVA_OPTS=

    ################################
    # Elasticsearch service
    ################################

    # SysV init.d
    #
    # The number of seconds to wait before checking if Elasticsearch started successfully as a daemon process
    ES_STARTUP_SLEEP_TIME=5

    # Heap new generation
    #ES_HEAP_NEWSIZE=

    # Maximum direct memory
    #ES_DIRECT_SIZE=

    # Additional Java OPTS
    ES_JAVA_OPTS=""

    # Configure restart on package upgrade (true, every other setting will lead to not restarting)
    #RESTART_ON_UPGRADE=true

    # Path to the GC log file
    #ES_GC_LOG_FILE={{ vitam_defaults.folder.root_path }}/log/{{ composant.cluster_name }}/gc.log

    ES_TMPDIR={{ vitam_defaults.folder.root_path }}/tmp/{{ composant.cluster_name }}

    ################################
    # Elasticsearch service
    ################################

    # SysV init.d
    #
    # When executing the init script, this user will be used to run the elasticsearch service.
    # The default value is 'elasticsearch' and is declared in the init.d file.
    # Note that this setting is only used by the init script. If changed, make sure that
    # the configured user can read and write into the data, work, plugins and log directories.
    # For systemd service, the user is usually configured in file /usr/lib/systemd/system/elasticsearch.service

    # Note: useless for VITAM, as the startup is managed by systemd
    ES_USER={{ vitam_defaults.users.vitamdb }}
    ES_GROUP={{ vitam_defaults.users.group }}

    # The number of seconds to wait before checking if Elasticsearch started successfully as a daemon process
    ES_STARTUP_SLEEP_TIME=5

    ################################
    # System properties
    ################################

    # Specifies the maximum file descriptor number that can be opened by this process
    # When using Systemd, this setting is ignored and the LimitNOFILE defined in
    # /usr/lib/systemd/system/elasticsearch.service takes precedence
    #MAX_OPEN_FILES=65536

    # The maximum number of bytes of memory that may be locked into RAM
    # Set to "unlimited" if you use the 'bootstrap.memory_lock: true' option
    # in elasticsearch.yml (ES_HEAP_SIZE  must also be set).
    # When using Systemd, the LimitMEMLOCK property must be set
    # in /usr/lib/systemd/system/elasticsearch.service
    #MAX_LOCKED_MEMORY=unlimited

    # Maximum number of VMA (Virtual Memory Areas) a process can own
    # When using Systemd, this setting is ignored and the 'vm.max_map_count'
    # property is set at boot time in /usr/lib/sysctl.d/elasticsearch.conf
    #MAX_MAP_COUNT=262144

## 7.2.4.2.5. Fichier `/usr/lib/tmpfiles.d/elasticsearch-log.conf`

    d    /var/run/{{ composant.cluster_name }}   0755 {{ vitam_defaults.users.vitamdb }} {{ vitam_defaults.users.group }} - -