DittoAndroidTools are diagnostic tools for Ditto. You can view connected peers, export debug logs, browse collections/documents and see Ditto's disk usage/ export this data.
These tools are available through Maven.
Issues and pull requests welcome!
- Android 8.0+
- Jetpack Compose
Ditto tools are released via Maven Central. Be sure to include it in your list of repositories.
repositories {
mavenCentral()
}
Tool Name | Gradle artifact |
---|---|
1. Tools Viewer | 'live.ditto:dittotoolsviewer:LIBRARY_VERSION' |
2. Presence Viewer | 'live.ditto:dittopresenceviewer:LIBRARY_VERSION' |
3. Data Browser | 'live.ditto:dittodatabrowser:LIBRARY_VERSION' |
4. Export Logs | 'live.ditto:dittoexportlogs:LIBRARY_VERSION' |
5. Disk Usage/Export Data | 'live.ditto:dittodiskusage:LIBRARY_VERSION' |
6. Health | 'live.ditto:health:LIBRARY_VERSION' |
7. Heartbeat | 'live.ditto:dittoheartbeat:LIBRARY_VERSION' |
8. Presence Degradation Reporter | 'live.ditto:presencedegradationreporter:LIBRARY_VERSION' |
You can find the list of versions and release notes in the Releases tab.
First, you must initialize Ditto:
val androidDependencies = DefaultAndroidDittoDependencies(applicationContext)
val identity = DittoIdentity.OnlinePlayground(androidDependencies, appId = "YOUR_APPID", token = "YOUR_TOKEN", enableDittoCloudSync = true)
ditto = Ditto(androidDependencies, identity)
DittoLogger.minimumLogLevel = DittoLogLevel.DEBUG
ditto.startSync()
NOTICE: This project loads ditto's credentials from local.properties
ditto.onlinePlayground.appId="YOUR_APPID"
ditto.onlinePlayground.token="YOUR_TOKEN"
Tools viewer is the easiest way to integrate all the tools currently available. It provides a single entry point to interact with all other tools, and includes them as a dependency.
It is available as a Composable element that requires a Ditto instance. Optional parameters include:
modifier
: If you need to adjust the layoutonExitTools
: Lambda function that will be called when the "Exit Tools" button is tapped. Use this to do any back navigation or dismissal of the tools composable if you need to.
Example code:
// minimum code required to get started
DittoToolsViewer(
ditto = YOUR_DITTO_INSTANCE
)
To integrate it in a Views-based app - see instructions here: https://developer.android.com/develop/ui/compose/migrate/interoperability-apis/compose-in-views
Download
Gradle:
dependencies {
implementation 'live.ditto:dittotoolsviewer:YOUR_LIBRARY_VERSION'
}
The Presence Viewer displays a mesh graph that allows you to see all connected peers within the mesh and the transport that each peer is using to make a connection.
Within a Composable, you pass ditto to the constructor:
DittoPresenceViewer(ditto = ditto)
Download
Gradle:
dependencies {
implementation 'live.ditto:dittopresenceviewer:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto</groupId>
<artifactId>dittopresenceviewer</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
The Ditto Data Browser allows you to view all your collections, documents within each collection and the propeties/values of a document. With the Data Browser, you can observe any changes that are made to your collections and documents in real time.
Within a Composable function, you pass ditto to the constructor:
DittoDataBrowser(ditto = ditto)
Standalone App
If you are using the Data Browser as a standalone app, there is a button, Start Subscriptions, you must press in order to start syncing data. If you are embedding the Data Browser into another application then you do not need to press Start Subscriptions as you should already have your subscriptions running.
Download
Gradle:
dependencies {
implementation 'live.ditto:dittodatabrowser:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto.</groupId>
<artifactId>dittodatabrowser</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
Export Logs allows you to export a file of the logs from your applcation.
Important
Before calling ditto.startSync()
we need to set the DittoLogger.setLogFileURL(<logFileURL>)
. This registers a file path where logs will be written to, whenever Ditto wants to issue a log (on top of emitting the log to the console). Use the LogFileConfig
struct:
object LogFileConfig {
private const val logsDirectoryName = "debug-logs"
private const val logFileName = "logs.txt"
val logsDirectory: Path by lazy {
val directory = Paths.get(System.getProperty("java.io.tmpdir"), logsDirectoryName)
Files.createDirectories(directory)
directory
}
val logFile: Path by lazy {
logsDirectory.resolve(logFileName)
}
}
and then before calling ditto.startSync()
set the log file url with:
LogFileConfig.logFile.let { logFile ->
DittoLogger.setLogFile(logFile.toString())
}
Now we can call ExportLogs()
.
ExportLogs(onDismiss: () -> Unit)
Download
Gradle:
dependencies {
implementation 'live.ditto:dittoexportlogs:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto</groupId>
<artifactId>dittoexportlogs</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
Disk Usage allows you to see Ditto's file space usage.
Export Data allows you to export the Ditto directory.
DittoDiskUsage(ditto = ditto)
Download
Gradle:
dependencies {
implementation 'live.ditto:dittodiskusage:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto</groupId>
<artifactId>dittodiskusage</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
Health allows you to see the status of Ditto's services.
Example: WiFi/Bluetooth state/permissions, device capabilities
The default implementation is a Composable that displays all facets of information.
HealthScreen()
This Composable also takes in an optional list of enum
's if you need to show/hide certain groups of information. Current valid enums are:
TRANSPORT_HEALTH -- shows WiFi/Bluetooth status (enabled/disabled, permissions state)
WIFI_AWARE_STATE -- displays whether the device supports WiFi Aware
Download
Gradle:
dependencies {
implementation 'live.ditto:health:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto</groupId>
<artifactId>health</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
The Ditto Heartbeat tool allows you to monitor, locally or remotely, the peers in your mesh.
Configure Heartbeat
These are the values you need to provide to the Heartbeat:
id
- Unique value that identifies the devicesecondsInterval
- The frequency at which the Heartbeat will scrape the datametaData
- Optional - any metadata you wish to add to the HeartbeathealthMetricProviders
List of HealthMetricProviderspublishToDittoCollection
- Optional - set to false to prevent from publishing the heartbeat to Ditto collection. Default true.
Available healthMetricProviders
:
- HealthViewModel() - health metrics for Permissions Health Tool
- DiskUsageViewModel() - health metrics for Ditto disk usage.
isHealthy
is determined by the size of theditto_store
andditto_replication
folders. The default isHealthy size is 2GB, but this can be configured.
There is a DittoHeartbeatConfig
data class you can use to construct your configuration.
// Provided with the Heartbeat tool
data class DittoHeartbeatConfig(
val id: String,
val secondsInterval: Int,
val metaData: Map<String, Any>? = null,
val healthMetricProviders: List<HealthMetricProvider>?,
val publishToDittoCollection: Boolean = true // Toggle to avoid publishing
)
// Example:
// User defines the values here
// Passed into Heartbeat tool
var healthMetricProviders: MutableList<HealthMetricProvider> = mutableListOf()
val diskUsageViewModel = DiskUsageViewModel()
diskUsageViewModel.isHealthyMBSizeLimit = 2048 //2GB worth of data
healthMetricProviders.add(diskUsageViewModel)
val config = DittoHeartbeatConfig(
id = <unique device id>,
secondsInterval = 30, //seconds
metaData = mapOf(
"deviceType" to "KDS"
),
healthMetricProviders = healthMetricProviders,
publishToDittoCollection = true
)
// Provide the config and your Ditto instance to startHearbeat()
startHeartbeat(ditto, config).collect { heartbeatInfo = it }
User Interface
You will need to provide your own UI. You can see an example here.
There are two ways you can access the data:
- The Ditto collection you provided
- startHeartBeat() provides a callback with the data
Ditto Collection:
This is the model of the data and what you can use for reference
{
_id: <ditto peerKey>,
_schema: String,
secondsInterval: String,
presenceSnapshotDirectlyConnectedPeersCount: Int,
lastUpdated: String (ISO-8601),
sdk: String,
presenceSnapshotDirectlyConnectedPeers: {
<peerKey>: {
deviceName: String,
sdk: String,
isConnectedToDittoCloud: Bool,
bluetooth: Int,
p2pWifi: Int,
lan: Int,
},
<peerKey>…,
…
},
metaData: {},
healthMetrics: {},
}
Callback:
You will receive a HeartbeatInfo
data class back
data class DittoHeartbeatInfo(
val id: String,
val schema: String,
val lastUpdated: String,
val metaData: Map<String, Any>?,
val secondsInterval: Int,
val presenceSnapshotDirectlyConnectedPeersCount: Int,
val presenceSnapshotDirectlyConnectedPeers: Map<String, Any>,
val sdk: String,
var healthMetrics: MutableMap<String, HealthMetric> = mutableMapOf()
)
Download
Gradle:
dependencies {
implementation 'live.ditto:dittoheartbeat:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto.</groupId>
<artifactId>dittoheartbeat</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
Tracks the status of your mesh, allowing to define the minimum of required peers that needs to be connected. Exposes an API to notify when the condition of minimum required peers is not met.
## UI Composable
PresenceDegradationReporterScreen(ditto = ditto)
## API
ditto.presenceDegradationReporterFlow().collect { state ->
// state.settings
// state.localPeer
// state.remotePeers
}
Download
Gradle:
dependencies {
implementation 'live.ditto:presencedegradationreporter:YOUR_LIBRARY_VERSION'
}
Maven:
<dependency>
<groupId>live.ditto</groupId>
<artifactId>presencedegradationreporter</artifactId>
<version>YOUR_LIBRARY_VERSION</version>
</dependency>
There are two ways you can test things locally. Either in the demo app, or in an external project.
To test your changes to a module in the demo app, simply import the local module, making sure to comment out/delete the version catalog import. For example, if you made changes to DittoDataBrowser you would
add: implementation(project(":DittoDataBrowser"))
remove/comment out: implementation libs.live.ditto.databrowser
- Run
./gradlew publishToMavenLocal
- In your external project add the
mavenLocal()
entry to your list of repository sources - When importing a tool, the version will be
SNAPSHOT
MIT