<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Operations Guide on Lucille</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/</link><description>Recent content in Operations Guide on Lucille</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 09 Jun 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/index.xml" rel="self" type="application/rss+xml"/><item><title>Configuration Management</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/configuration/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/configuration/</guid><description>&lt;p&gt;This page covers the operational patterns for working with Lucille&amp;rsquo;s configuration system — how to use environment variable substitution, how to compose configs from reusable files, how to deploy configs in containers, and how to validate configs before running. For the architectural rationale behind Lucille&amp;rsquo;s choice of HOCON and the Typesafe Config library, see &lt;a href="https://kmwtechnology.github.io/lucille/docs-0.10.0/architecture/components/config/"&gt;Architecture: Config&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="environment-variable-substitution"&gt;Environment Variable Substitution&lt;/h2&gt;
&lt;p&gt;In containerized deployments (Docker, Kubernetes), credentials and environment-specific settings are typically provided via container environment variables or mounted secrets. A database password, an API key, a search engine URL — these should not be hardcoded in a config file that lives in version control.&lt;/p&gt;</description></item><item><title>Logging Setup</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/logging/</link><pubDate>Wed, 07 May 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/logging/</guid><description>&lt;h2 id="lucille-logs"&gt;Lucille Logs&lt;/h2&gt;
&lt;p&gt;Lucille uses Log4j2 (via SLF4J) for all logging. A default &lt;code&gt;log4j2.xml&lt;/code&gt; is included in &lt;code&gt;lucille-core/src/main/resources/&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="using-a-custom-log4j2-configuration"&gt;Using a Custom Log4j2 Configuration&lt;/h3&gt;
&lt;p&gt;To override the default logging configuration, pass the standard Log4j2 system property on the Java command line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;java -Dlog4j.configurationFile&lt;span style="color:#ce5c00;font-weight:bold"&gt;=&lt;/span&gt;/path/to/my-log4j2.xml &lt;span style="color:#4e9a06"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -Dconfig.file&lt;span style="color:#ce5c00;font-weight:bold"&gt;=&lt;/span&gt;my-pipeline.conf &lt;span style="color:#4e9a06"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -cp &lt;span style="color:#4e9a06"&gt;&amp;#39;target/lib/*&amp;#39;&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; com.kmwllc.lucille.core.Runner
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This applies to all Lucille components (Runner, Worker, Indexer, WorkerIndexer). If you don&amp;rsquo;t provide this property, Log4j2 uses whatever &lt;code&gt;log4j2.xml&lt;/code&gt; it finds on the classpath.&lt;/p&gt;</description></item><item><title>Log Interpretation</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/log-analysis/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/log-analysis/</guid><description>&lt;h2 id="log-format"&gt;Log Format&lt;/h2&gt;
&lt;p&gt;Lucille uses SLF4J with Log4j2 as the logging backend. The log format depends on your Log4j2 configuration:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plain text (typical console/file output):&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;2026-05-06 20:51:53.581 INFO [main] c.k.l.c.Runner - Pipeline Configuration is valid.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;JSON (structured logging for log aggregation):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#000;font-weight:bold"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;@timestamp&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;2026-05-06T20:51:53.581Z&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;log.level&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;INFO&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;Pipeline Configuration is valid.&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;process.thread.name&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;log.logger&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;com.kmwllc.lucille.core.Runner&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#204a87;font-weight:bold"&gt;&amp;#34;run_id&amp;#34;&lt;/span&gt;&lt;span style="color:#000;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#4e9a06"&gt;&amp;#34;c1d9413a-...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#000;font-weight:bold"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The JSON format includes the &lt;code&gt;run_id&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; (document ID) fields from the MDC, making it possible to filter logs by run or by document in log aggregation tools. In plain text mode, only the &lt;code&gt;message&lt;/code&gt; field is typically visible.&lt;/p&gt;</description></item><item><title>Performance Tuning</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/performance-tuning/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/performance-tuning/</guid><description>&lt;h2 id="before-you-optimize-choosing-the-right-deployment-mode"&gt;Before You Optimize: Choosing the Right Deployment Mode&lt;/h2&gt;
&lt;p&gt;Distributed mode provides a pathway to higher throughput by running multiple Worker and Indexer processes across machines. However, there is inherent overhead in serializing and deserializing documents across Kafka and process boundaries — every document is converted to JSON, written to Kafka, read from Kafka, and parsed back into a Document object at each hop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distributed mode is not necessary or justified for all projects.&lt;/strong&gt; For a small ingestion task (thousands to low millions of documents with lightweight enrichment), local single-JVM mode is often sufficient and faster end-to-end than distributed mode because it avoids all serialization overhead. The in-memory queues in local mode have near-zero latency compared to Kafka round-trips.&lt;/p&gt;</description></item><item><title>Security Configuration</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/security/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/security/</guid><description>&lt;p&gt;Lucille connects to external systems — search backends (Solr, OpenSearch, Elasticsearch, Pinecone) and Kafka — that may require TLS encryption and authentication. This page covers how to configure security for each.&lt;/p&gt;
&lt;h2 id="general-principles"&gt;General Principles&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Never hard-code credentials in config files.&lt;/strong&gt; Use HOCON&amp;rsquo;s environment variable substitution to inject secrets at runtime:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-hocon" data-lang="hocon"&gt;opensearch {
 url: &amp;#34;https://localhost:9200&amp;#34;
 url: ${?OPENSEARCH_URL} # override from env var
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In Kubernetes, inject credentials via Secrets mounted as environment variables. In Docker, use &lt;code&gt;--env&lt;/code&gt; or &lt;code&gt;--env-file&lt;/code&gt;. The config file can live in version control with defaults; secrets come from the environment.&lt;/p&gt;</description></item><item><title>REST API</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/api/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/api/</guid><description>&lt;p&gt;The &lt;code&gt;lucille-api&lt;/code&gt; plugin adds an HTTP REST API built on &lt;a href="https://www.dropwizard.io/"&gt;Dropwizard&lt;/a&gt; that allows managing configs and triggering runs over HTTP rather than via the CLI. It includes a Swagger UI and optional basic authentication.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Current limitation:&lt;/strong&gt; The REST API launches all runs in local mode (in-memory queues, Workers and Indexer as threads within the API server&amp;rsquo;s JVM). It cannot currently trigger a distributed Kafka-based ingest. If you need distributed mode, use the CLI Runner with &lt;code&gt;-usekafka&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Support Matrix</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/support-matrix/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/support-matrix/</guid><description>&lt;h2 id="java"&gt;Java&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Version&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Java 21&lt;/td&gt;
 &lt;td&gt;Supported (minimum required)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Lucille is compiled targeting Java 21. This version is tested in CI via GitHub Actions using Eclipse Temurin distributions.&lt;/p&gt;
&lt;h2 id="build-tool"&gt;Build Tool&lt;/h2&gt;
&lt;p&gt;Apache Maven 3.x is required to build Lucille from source.&lt;/p&gt;
&lt;h2 id="search-backends"&gt;Search Backends&lt;/h2&gt;
&lt;p&gt;The following backends are supported via the Indexer component.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Backend&lt;/th&gt;
 &lt;th&gt;Tested Version&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Apache Solr&lt;/td&gt;
 &lt;td&gt;9.x&lt;/td&gt;
 &lt;td&gt;Client: &lt;code&gt;solr-solrj&lt;/code&gt; 9.8.0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;OpenSearch&lt;/td&gt;
 &lt;td&gt;2.x&lt;/td&gt;
 &lt;td&gt;Client: &lt;code&gt;opensearch-java&lt;/code&gt; 2.11.1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Elasticsearch&lt;/td&gt;
 &lt;td&gt;8.x&lt;/td&gt;
 &lt;td&gt;Client: &lt;code&gt;elasticsearch-java&lt;/code&gt; 8.18.4&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CSV&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;Writes indexed documents to a local CSV file; no server required&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Nop&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;Discards output; used for testing and dry runs&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="kafka-distributed-mode"&gt;Kafka (Distributed Mode)&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Component&lt;/th&gt;
 &lt;th&gt;Version&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;kafka-clients&lt;/td&gt;
 &lt;td&gt;4.0.0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Kafka broker&lt;/td&gt;
 &lt;td&gt;3.x, 4.x&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Kafka is only required when running in distributed mode (&lt;code&gt;-usekafka&lt;/code&gt;). Local mode uses in-memory queues and has no Kafka dependency.&lt;/p&gt;</description></item><item><title>Troubleshooting</title><link>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/troubleshooting/</link><pubDate>Tue, 15 Oct 2024 00:00:00 +0000</pubDate><guid>https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/troubleshooting/</guid><description>&lt;p&gt;If something isn&amp;rsquo;t working, &lt;strong&gt;read logs first&lt;/strong&gt;. Lucille logs are detailed and will usually identify where the problem is coming from. See &lt;a href="https://kmwtechnology.github.io/lucille/docs-0.10.0/operations/log-analysis/"&gt;Log Analysis&lt;/a&gt; for a guide to reading Lucille logs.&lt;/p&gt;
&lt;h2 id="debugging-failed-documents"&gt;Debugging Failed Documents&lt;/h2&gt;
&lt;p&gt;The run summary reports how many documents failed, but not which ones or why. Here&amp;rsquo;s the workflow for investigating failures.&lt;/p&gt;
&lt;h3 id="step-1-find-the-failed-document-ids-and-reasons"&gt;Step 1: Find the failed document IDs and reasons&lt;/h3&gt;
&lt;p&gt;Search the logs for failure messages. These are logged at ERROR level by the DocLogger. All document failures use a standardized &lt;code&gt;&amp;quot;Document FAILED&amp;quot;&lt;/code&gt; prefix, so you can find every failure in one pass and then drill into specific types:&lt;/p&gt;</description></item></channel></rss>