Configuration variables are dynamic values that can be injected to modify the behavior of an application without making changes to the code. Configuration variables are often used as a mechanism to control various aspects of an application's functionality, such as database connections, API keys and secrets, feature toggles, logging levels, and many more.
Since the release of Fermyon's Spin `v1.3.0`, configuration variables can be externalized from application code and deployed to Fermyon cloud. Using the `spin cloud variables` command, you can update the deployed application's configuration without having to restart or modify code!
In this post we will discuss several usecases for configuration variables when developing and deploying Spin applications to Fermyon cloud and then explore a concrete example application of using configuration to control the applications logging verbosity.
## Utilize configuration variables to ...
* Manage Sensitive Data: Fermyon's configuration feature allows you to isolate your application’s sensitive data such as passwords, certificates, encryption keys, or API tokens away from your application's business logic. Through utilizing configuration in conjunction with `spin cloud variables`, you can easily manage and update your application’s security configurations as needed maintaning a strong security posture for your deployed application.
* Integrate with External Services: Your application may interface external databases, message queues, or third-party APIs. Using Fermyon’s configuration feature you can inject information about these systems at deploy time and update as needed without modifying the application code.
* Control logging verbosity: Application's are often deployed with default logging settings such as verbosity. In the event that you are seeing unexpected errors or behavior, it's useful to be able to adjust the verbosity of your logging at runtime to get real time, production information to properly diagnose potential bugs.
* Toggle availability of specific features: Using dynamic configuration to enable or disable the availability of specific features within your application allows for gradually rolling out features and faciliates A/B testing.
# An Example
In this example we will build a simple `Rust` application that demonstrates how to dynamically configure the logging level for a Spin application without redploying or modifying the code.
Before continuing, ensure that you have Spin v1.3.0 or greater installed. You can follow the official Fermyon Cloud Quickstart guide to [install Spin](/cloud/quickstart#install-spin) and [log into Fermyon Cloud](/cloud/quickstart#log-in-to-the-fermyon-cloud).
Let's start by [creating a new Spin application](/cloud/cli-reference#new) using the `http-rust` template. Follow the steps below:
```bash
$ spin new http-rust my-logging-app
Project description: A Spin app that logs the request method and URL
HTTP base: /
HTTP path: /...
```
## Adding the configuration variable to our application
Next, let's add our `loglevel` configuration variable to our `Spin.toml`.
```toml
# Add this above the [component] section
[variables]
loglevel = { default = "info" }
```
Then we will add a `[component.config]` section that effectively gives our component access to our dynamic configuration variable:
```
# Add this below the `[component.build] section`
[component.config]
loglevel = "{{ loglevel }}"
```
In total, our `spin.toml` should now look something like:
```toml
spin_manifest_version = "1"
description = "A Spin app that logs the request method and URL"
name = "my-logging-app"
trigger = { type = "http", base = "/" }
version = "0.1.0"
[variables]
loglevel = { default = "info" }
[[component]]
id = "my-logging-app"
source = "target/wasm32-wasi/release/my_logging_app.wasm"
[component.trigger]
route = "/..."
[component.build]
command = "cargo build --target wasm32-wasi --release"
[component.config]
loglevel = "{{ loglevel }}"
```
## Implementing our application
Before we dive in, let's add the Rust `log` and `simple_logger` dependency to our `Cargo.toml`:
```bash
$ cargo add log simple_logger
```
Now that we have declared our configuration variable and added our rust dependencies, we are ready to implement our Spin application.
In `lib.rs`:
```rust
use log::*;
use anyhow::{anyhow, Result};
use simple_logger::SimpleLogger;
use spin_sdk::{
config,
http::{Request, Response},
http_component,
};
// This function will initialize logging for our application. The logger
// will be configured to log at the level indicated by the value of our
// dynamic configuration variable "loglevel".
fn init_logger() -> Result<()> {
// The name of our dynamic configuration variable.
const LOG_LEVEL_CONFIG_VARIABLE: &str = "loglevel";
// Use the config SDK to get the value of loglevel and
// transform it into a known `log::LevelFilter`.
let level: LevelFilter = config::get(LOG_LEVEL_CONFIG_VARIABLE)?
.parse()
.map_err(|e| anyhow!("parsing log level: {e}"))?;
// Finally initialize the logger.
SimpleLogger::new()
.with_level(level)
.init()?;
Ok(())
}
// Our HTTP event handler
#[http_component]
fn handle_my_logging_app(req: Request) -> Result<Response> {
// Initialize the logger.
init_logger()?;
// Log the method and URI at the TRACE level.
trace!("method={}, uri={}", req.method(), req.uri());
// ... do some work and handle the request ...
// Log message indicating success at INFO level.
info!("returning 200");
Ok(http::Response::builder()
.status(200)
.body(None)?)
}
```
Now that we have implemented our simple application, let's build and deploy to Fermyon cloud:
```bash
$ spin build
$ spin deploy
Uploading my-logging-app version 0.1.0+rb410cbfe...
Deploying...
Waiting for application to become ready......... ready
Available Routes:
my-logging-app: https://my-logging-app-uaeligif.fermyon.app (wildcard)
```
To verify that our configuration has been successfully associated with our app, we can use `spin cloud variables` command to inspect the set of variables:
```bash
$ spin cloud variables list
loglevel
```
If we execute a request to our available route:
```bash
$ curl https://my-logging-app-uaeligif.fermyon.app
```
... we should see an `INFO` log message in `cloud.fermyon.com` application's dashboard similar to:
```
2023-06-26T20:25:39.040Z INFO [my-logging-app] returning 200
```
Notice how we don't see the `TRACE` level log of the method and URI because we declared our configuration variable to default to INFO.
However, we can use `spin cloud variables set` to update the value of "loglevel" configuration to `TRACE`:
```bash
$ spin cloud variables set loglevel=trace --app my-logging-app
```
If we execute the request from above again, we will see our application is now logging our requests method and URI:
```
2023-06-27T13:58:24.967Z TRACE [my-logging-app] method=GET, uri=/
```
# Until next time
As we have seen, there are many valuable uses of Fermyon's configuration feature. We'd love to hear yours! If you want to share your ideas or ask questions drop in to the [Fermyon Discord server](https://discord.gg/AAFNfS7NGf) or say hello on Twitter [@fermyontech](https://twitter.com/fermyontech/) and [@spinframework](https://twitter.com/spinframework).
To dig deeper, be sure to check out the documentation for [Application Configuration Variables](/cloud/variables).