Using an Application Identity
Tags: identity, application, kotlin, diagnostics
Published: 2021-02-16 02:33:12

This post discusses using an **application identity** ( a `convention based unique name to identify any app` ) to organize, identify an application, and properly link the identity to the **logs, metrics, alerts, and other diagnostics** of the application. This was designed for a Kotlin framework called [Slate Kit](https://www.slatekit.com); codebase at [Git](https://github.com/slatekit/slatekit), and code for this component here at [Identity.kt] (https://github.com/slatekit/slatekit/blob/main/src/lib/kotlin/slatekit-common/src/main/kotlin/slatekit/common/Identity.kt). 

# Example
We use the convention below to create a unique name representing the identity of any application. This name uniquely identifies an application, provides **ownership, environment, version info** and is used to appropriately link it to various diagnostics( logs, alerts, metrics) when running. 
```bash
{area}.{name}.{type}.{env}.{version}.{instance}
signup.alerts.job.qat.v2.4a3b300b-d0ac-4776-8a9c-31aa75e412b3
```

# Real-World
We already have conventions for identifying various resources, some obvious examples in the real world are below. So why not have one for an application ?
- **uri**: `https://github.com/slatekit/slatekit` - account + repo 
- **ip** : `129.144.59.56` - network + host 
- **phone** : `800-123-4567` - u.s phone format 
- **SSN** :   `123-45-6789` - u.s Social Security Number

# Use-cases
The examples above clearly resolve the value to a computer or a person. This allows for supporting a lot of other things like lookup, ownership, tracing, and diagnostics. A production application usually involves the following
- **ownership** : simply knowing who owns/manages an app
- **logs** : log for info, debug, warnings, errors
- **metrics**: metrics being sent to providers like newrelic/datadog
- **alerts** : alerts being sent out ( e.g. pagerduty, slack )

An identity is especially useful for organizations that could have dozens to hundreds of applications. But even for small groups, startups, side projects, an identity can come in handy to **distinguish between a background job, an api, or a bot** that may all be related to a specific product area or service. 

# Packages
One way to typically identify a **running** app is to simply use a **git repo** and some type of **namespace** ( e.g. java package name ) to serve as some form of identity. For example [slatekit.samples](https://github.com/slatekit/slatekit/blob/main/src/apps/kotlin/slatekit-samples/src/main/kotlin/slatekit/samples/Samples.kt#L1). But this is pretty vague doesn't contain useful information. It also says nothing about what **type** of app it is, its **environment, version** info, and/or some other attributes. 
```kotlin
app: github.com/account/app
package : slatekit.samples
```
The package name may be used in logs, metrics. `But a package name is a loose standard with not enough info, especially for a running app.`

# Solution
A simple solution is to come up with a **strict** naming convention for the identity of app ( and enforced in code ) that can capture some important attributes to build the name or identity. I've decided on the following convention. 
```bash
{area}.{name}.{type}.{env}.{version}.{instance}
signup.alerts.job.qat.v2.4a3b300b-d0ac-4776-8a9c-31aa75e412b3
```
This examples represents a background **job** we use in the **signup/registration** portion of an mobile app being worked on, that generates **alerts, emails, sms** confirmations in a **test/qat** environment. It also contains the version number and instance id ( which is newly generated as a simple uuid on each deployment ) and also distinguishers between multiple instances of the application.

# Attributes
I've decided to include the following attributes in the identity of an app. These parts can also be used to generate a short-form or long-form id for convenience.

| Attribute      | Example | Purpose |
| ----------- | ----------- |----------- |
| **area**   | signup | product area / department |
| **name**   | alerts | name of the application |
| **type**   | job    | `cli , api , job , bot` |
| **env**    | qat    | `dev , qat , uat , pro` |
| **ver**    | v2-1   | version of app |
| **uuid**   | id     | instance id  |

With these attributes, you can generate short or long form identities. For example :
```bash
Short id
# {area}.{name}.{type}.{env}
"signup.alerts.job.qat"

Version id
# {area}.{name}.{type}.{env}
"signup.alerts.job.qat.v2"

Full Id
# {area}.{name}.{type}.{env}.{version}.{instance}
"signup.alerts.job.qat.v2.4a3b300b-d0ac-4776-8a9c-31aa75e412b3"
```

# Code
The application identity is strictly enforced in code using the [Identity.kt] (https://github.com/slatekit/slatekit/blob/main/src/lib/kotlin/slatekit-common/src/main/kotlin/slatekit/common/Identity.kt) class and enums for the types, environments. 

```kotlin
/**
 * Simple Identity used to identity services / components
 * @param area    : area  | dept | org  - logical group 
 * @param service : user1 | job  | svc  - name of app/service
 * @param agent   : api   | app  | job  - type of app
 * @param env     : dev   | qat  | pro  - environment
 * @param instance: UUID                - for 2+ instances
 *
 *      = {area}.{service}.{agent}.{env}.{version}.{instance}
 * name = signup.alerts.job.qat
 * full = signup.alerts.job.qat.v2.4a3b300b-d0ac-4776-8a9c-31aa75e412b3
*/
data class SimpleIdentity(
        override val area:String,
        override val service:String,
        override val agent: Agent,
        override val env:String,
        override val instance:String = ULIDs.create().value,
        override val version: String = "LATEST",
        override val desc: String = "",
        override val tags:List<String> = listOf()) : Identity {
  // ... 
}
```

# Diagnostics
We identify applications using this approach and use the full-id and use its attributes when linking it to slack alerts, logs and metrics. Here are some samples for Slack and Loggly.

## Alerts
Here is a sample Slack alert with the identity of the application that sent the alert in the **origin** field.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i7tcnq76o37qv5lye763.png)

## Logs 
Here is a simple example of a log entry with the identity of the application prefixed ( in both a local log file and sent to Loggly ).
```txt
signup.alerts.job.qat.v2.2.0: 2021-02-15 17:25 INFO [main] app Beta user activated   , uuid=0a32988c-4eed-42dc-8ba7-b932d82da3f0, phase=2
signup.alerts.job.qat.v2.2.0: 2021-02-15 17:26 INFO [main] app user welcome mail sent, uuid=0a32988c-4eed-42dc-8ba7-b932d82da3f0, phase=2
```

Because the identity is enforced in code and in configurations for various diagnostics, we now have a way of easily identifying apps and connecting/searching diagnostics more easily!

# Registry
With application identities defined, you can also create a dashboard to serve as an **application registry** that lists all applications running in your environments.

# Customize
All these attributes collectively provide a unique identity that can assist with ownership, and most importantly link with and provide insight into diagnostics and metrics. If you're using Kotlin for Server or Android, then checkout  [Identity.kt] (https://github.com/slatekit/slatekit/blob/main/src/lib/kotlin/slatekit-common/src/main/kotlin/slatekit/common/Identity.kt) or build your own!