Added In
KOS Version
Module
KOS Core
Compatible with:
Introduction
The analytics package provides the services, data structures, and extension points used to record, classify, and export analytics data in KOS. Analytics are structured events captured at the moment they occur and are intended for business and operational insights rather than developer debugging. Their consistent structure makes them easy to aggregate, enabling trend analysis, performance measurement, and visibility into real-world device behavior at scale. To ensure reliability, KOS provides built-in support for event prioritization, batching, retries, and multi-node synchronization. These capabilities allow analytics data to be captured and exported efficiently and robustly, even in distributed systems or environments with intermittent connectivity.
Analytics Data Flow

FAQs
Analytics data should capture information that helps you understand trends, measure performance, and make business decisions. In short, analytics feed reporting and tend to be data that other teams need captured. This is in contrast to log files. While log files can be processed to extract data for reports, logs tend to be developer-centric and tend not to guarantee formatting or consistency over time.
Logging is for developers: it captures technical details used to monitor, debug, and troubleshoot the device. Examples include error messages, warnings, or stack traces.
Analytics are meant for business decisions and operational insights. Analytic events can be aggregated over time to reveal trends, patterns, and performance metrics.
Analytics should contain structured information that helps reveal trends, patterns, and performance over time. The data should be directly useful for business or operational decisions. As analytics are JSON serialized objects, a single analytic event can contain considerable structured data, allowing back end systems to more easily identify complex scenarios in the the field. Analytic data is commonly defined as a collaboration between device developers and back end data engineers.
AnalyticsExporter and bind it to a channel. KOS will automatically bundle together events and notify the exporter to send the data, automatically handling failures and retries. To catch all the analytic events and to catch the earliest events you can implement the AnalyticsDefaultChannelExporter. The diagram at the top is a visualization of this process.Analytics events can be any JSON serializable object that represents structured data you want to capture for business or operational insights. Commonly, these are simple data objects, maps, or custom classes that include fields like timestamps, IDs, counts, or measurements.
The key requirement is that the object is JSON serializable so it can be stored and exported by KOS. By default, analytic data objects are serialized using the Analytics.View JsonView, although custom views can be specified as needed.
- Using the
AnalyticsService- Synchronous recording – call
record()to store the event on the calling thread. This is the recommended method as the overhead is minimal. - Asynchronous recording – call
recordAsync()to queue the event for recording on a background thread. This is intended for situations where even minimal blocking on the calling thread must be avoided, such as in highly time-sensitive operations.
AnalyticsServiceby autowiring it into your component. - Synchronous recording – call
- Using the static accessor
- Call
KosCore.getAnalytics()directly to record events without autowiring.
- Call
AnalyticsClassifier instances into channels and stored locally until exported via AnalyticsExporter instances.AnalyticsService in two ways:- Autowiring: Inject it into your component using your dependency injection framework.
- Static accessor: Call
KosCore.getAnalytics()directly to record events. This avoids the need to inject this interface in difficult to reach code paths that want to record events.
KOS does not enforce size constraints when recording events, but will prune data from local disk based on overall storage limits. Cloud based services may impose their own payload size limits which may impact the ability to export data. In general, analytic events tend to be relatively small and contain enough information to be linked together with other data in back end reporting processes.
KOS facilitates the process of recording, classifying and exporting analytic data to external systems such as cloud infrastructure. It is not intended as a mechanism to record data for on-device use.
Every analytic event consists of type and an associated data payload. The type identifies the event being recorded while the data payload contains the information associated with the event. It’s entirely possible that multiple types use the same payload. For example, the events that record that a particular item was added and removed may have distinct types, but include the same data, which may be the item being added or removed.
There is no central registry for event types and developers are free to define new types as needed. However, as KOS is an application based platform, if developers aren’t careful, it’s possible for different applications on the same device to use the same type name for different events. To avoid this, is is recommended that all type names be namespaced to your organization, similar to DNS domain names. For example, types defined by Acme Corp may start with a prefix of “acme.” in order to guarantee no other applications use the same type name.
Another consideration in selecting a type is the classification process. Events are mapped to channels via classifiers that only have access to the event type. If a classifier needs to record all the events related a particular function, the implementation would be easier if all of these events shared a common type prefix. For example, if all pouring events have a prefix of “acme.pour.” then the classifier simply needs to look for this prefix, instead of needing to know every possible pouring related event type.
Yes. Analytic event types should be written as lowercase, dot-separated strings that follow a namespace-like structure.
- Non-serializable object: The object passed to
record()must be JSON-serializable. If it cannot be serialized, the exported data may be empty. - Issues with JSON view: Each call to
record()has an associated JsonView that controls how the data is serialized to JSON. By default, the view isAnalyticsEvent.View, but it can be overridden to use a custom view or set tonullto use no view at all. While usingnullwill include all fields, this must be done with caution:- Fields referencing complex objects (like
Assembly) may contain nested classes that do not serialize correctly. - Future additions to the class may unintentionally include non-serializable fields, leading to empty or broken events.
- When attempting to use complex objects as data for an event, it is safer to explicitly annotate only the fields that should be included using
@JsonView. This ensures predictable and safe serialization.
- Fields referencing complex objects (like
- Classifier misconfiguration: If the event does not appear in the database at all, there is likely no classifier that maps this event to a channel. Only events that are mapped to channels are stored locally for export.
Priority levels determine how quickly associated exporters are called based on the priority of the data. KOS does not segment data by priority, it is simply used to indicate how quickly an associated exporter should be called to export data. For example, consider a 30 minute delay for low priority events and a one minute delay for high priority events. If the first event recorded is low priority, a 30 minute timer will be triggered. If another low priority event is recorded, the existing timer will be reduced to 30 minutes. Since the timer is already running and less then 30 minutes, the timer remains unchaged. If a high priority event is recorded, the existing timer is reduced to one minute. When the timer fires, it will send the maximum allowable data to the exporter, including all events that have been recorded.
AnalyticsService configuration settings as well as the AnalyticsExporter implementation:- When you are implementing the
AnalyticsExporteryou can override thegetAnalyticsPriorityDelay()method to specify the delay of Priority levels for that exporter. If not overridden, the default values fromApplicationServerwill be used. - For device-wide changes, you can override the configuration settings of
ApplicatonServer, which will apply to any exporters that do not explicitly overridegetAnalyticsPriorityDelay().
recordAsync() or record() in the AnalyticsService. Alternatively, you can use convenience methods like recordHigh() to automatically assign a high priority without explicitly passing it. It is generally recommended to set priority to low unless the event needs to be reviewed immediately.flush() method in the AnalyticsServer. This flushed the contents of a specific channel, causing the exporter associated with the channel to be called immediately with any pending analytic events.- Using
AnalyticsServerConfigin the “Configuration Viewer”: you can specify the maximum number of rows to export in a single call. Smaller batches reduce latency but increase network traffic, while larger batches reduce the number of requests but may increase the time to process individual events. - Additionally, when you are implementing the
AnalyticsExporter, you must specify the maximum size of data the exporter can handle in a single export call, along with the the minimum size of data required to trigger an export.
AnalyticsService to record events:- Synchronous recording – call
record()to store the event on the calling thread. This is the recommended method as the overhead is minimal. - Asynchronous recording – call
recordAsync()to queue the event for recording on a background thread. This is intended for situations where even minimal blocking on the calling thread must be avoided, such as in highly time-sensitive operations.
Yes! Events are classified to channels for local storage and then exported via channel exporters. KOS allows classifiers to pick which events are put in which channels so exporting a single event to multiple destinations is simply a matter of classifying the event into more than one channel.
AnalyticsClassifiers, which are then persisted locally. Each channel can have a single AnalyticsExporter which is responsible for exporting the persisted data to some external system. Once successfully exported, the events will be removed from the channel. By default, all events are sent to the AnalyticsServer.DEFAULT_CHANNEL.AnalyticsServer.DEFAULT_CHANNEL. As this classifier is set early in the boot process, it can capture events that other classifiers cannot. Typically, the system agent will provide an exporter for this channel. Since KOS provides a default classifier, the only reason to add additional classifiers is to send a subset of the analytic stream to another destination. For example, a business partner may require certain events to drive their business case. They can add a classifier and exporter to extract the data they need directly from the device.AnalyticsServer on the primary node. This means you simply need to implements the AnalyticsClassifier interface and put the bean into a BeanContext that is visible to the top level KOS BeanContext. The classifier will automatically be called for all new events.AnalyticsEvent: This class can be used either as a base class for event data or as a wrapper for existing objects when recording events via theAnalyticsService. EachAnalyticsEventincludes a timestamp, type, priority, view, and data. The data must be JSON-serializable.AnalyticsRecord: That act of recording an event converts the event data into JSON form. This effectively converts theAnalyticsEventobject, which contains java data, to anAnalyticsRecordobject which contains a JSON representation of the data. These records are then passed toAnalyticsClassifiersto be persisted into channels. In multi-node systems, this format is used to transfer analytic events to the primary node for classification and persistence in channels.AnalyticsExportBean: This is used when exporting events to external destinations via anAnalyticsExporter. This object is optimized for bulk JSON serialization for use by exporters and removes transient data contained by the earlier formats. These objects are intended for export only.
No. In a multi-node device, all analytic events on secondary nodes are cached locally and then sent to the primary node for classification and export. This is entirely transparent to the developer and no special considerations need to be made when logging analytic events on secondary nodes. Since secondary nodes are not guaranteed to have an external network connection, this ensures that all data classification and exporting is centrally managed on the primary node.
Each analytics channel can have only one registered exporter. This is because a channel persists the events assigned to the channel until they are exported. Once the exporter successfully exports a block of events, these events will be removed from the channel. If multiple destinations need the same data, you can assign the same events to multiple channels, each with its own exporter.
AnalyticsExporter. This allows a single exporter to send multiple distinct data streams without the need to create multiple exporter instances. As the exporter is provided with the channel name for every export attempt, a single exporter can use the channel name to determine how to process the data.- You can register an
AnalyticsExporterwith a channel by using theregister()method inAnalyticsServer. Similarly, you can also remove it by callingunregistered(), for example if the channel’s data needs to be exported to a different destination. AsAnalyticsServeris in the top level KOSBeanContext, you can simply autowire it to get access to it as needed. - Your exporter can be autowired automatically by implementing the
AnalyticsChannelExporterinterface. This interface identifies the associated channel so you simply need to create an instance and put the bean into aBeanContextthat is visible to the top level KOSBeanContext.
AnalyticsExpoerter without registering it to a channel, but it servers no purpose. Channels need exporter, otherwise, all their event data is eventually purged. Similarly, exporters need channels: otherwise, they never receive event data to export.AnalyticsServer.DEFAULT_CHANNEL. This classifier is set early in the boot process, therefore it can capture events that other classifiers cannot.Since every channel represents a persistent copy of analytic events, having a channel with no exporter will simply fill the local database with events that are never used. The service will purge the data by size and date. So, while a channel without an exporter will not cause issues, it is not particularly useful.
AnalyticsExporter: This is a generic interface that is responsible for exporting analytics beans to a destination. Exporters are registered with a channel name, andAnalyticsServerwill call the exporter with beans to export based on events, timers and policy implemented in the core service. The exporter just exporters data and indicates success. If successful, the beans are deleted from the device. If not successful (throws an exception), the beans will remain cached locally and will be send to the exporter again in the future to retry the export. It is possible to register anAnalyticsExporterto multiple channels, in order to send multiple distinct data streams to a single destination.AnalyticsChannelExporter: AnAnalyticsExporterthat is a bound to a single channel. This is a convenience interface:instances of this interface will automatically be registered with theAnalyticsServervia autowiring.AnalyticsDefaultChannelExporter: This is also a convenience interface. Specifically, it is anAnalyticsChannelExporterthat is bound to the default KOS analytics channel,AnalyticsServer.DEFAULT_CHANNEL. Note that only a single exporter can be registered per channel, so typically only the system agent should register the default channel.
AnalyticsEvent when creating the event. The view controls how the data is serialized to JSON. By default, the view is AnalyticsEvent.View. Setting the view to null disables JSON view entirely.