forked from airlift/airlift
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
An initial stab at Airlift documentation
I used Dropwizard as a template. Note: this is only a first attempt. If you like this direction I will continue otherwise let me know what to do differently.
- Loading branch information
Showing
11 changed files
with
857 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
[◀︎ Airlift](../README.md) • [◀︎ Getting Started](getting_started.md) • [◀︎ Next Steps](next_steps.md) | ||
|
||
## Add Configuration | ||
|
||
Airlift's Configuration support is simple and straightforward. Let's add configuration to our | ||
example project. | ||
|
||
Currently, the message returned by the `hello()` method is hard coded. Let's make it configurable: | ||
|
||
### Step 1 - Add Needed Dependencies | ||
|
||
We need a few additional dependencies. Add the following to the dependencies section of your | ||
`pom.xml` file: | ||
|
||
```xml | ||
<dependency> | ||
<groupId>javax.validation</groupId> | ||
<artifactId>validation-api</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.airlift</groupId> | ||
<artifactId>configuration</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>javax.inject</groupId> | ||
<artifactId>javax.inject</artifactId> | ||
</dependency> | ||
``` | ||
|
||
### Step 2 - Create the Config Class | ||
|
||
Create `src/main/java/example/ServiceConfig.java` with the following content: | ||
|
||
```java | ||
package example; | ||
|
||
import io.airlift.configuration.Config; | ||
|
||
import javax.validation.constraints.NotBlank; | ||
|
||
public class ServiceConfig | ||
{ | ||
private String helloMessage = "Hello Airlift!"; | ||
|
||
@NotBlank | ||
public String getHelloMessage() | ||
{ | ||
return helloMessage; | ||
} | ||
|
||
@Config("hello.message") | ||
public ServiceConfig setHelloMessage(String helloMessage) | ||
{ | ||
this.helloMessage = helloMessage; | ||
return this; | ||
} | ||
} | ||
``` | ||
|
||
### Step 3 - Bind the Config Class | ||
|
||
We need to bind the Config class in our Guice module. Airlift's `configBinder` is used for this. | ||
Edit your `ServiceModule.java` file so that it looks like this (add the new import and new binding): | ||
|
||
```java | ||
package example; | ||
|
||
import com.google.inject.Binder; | ||
import com.google.inject.Module; | ||
|
||
import static io.airlift.configuration.ConfigBinder.configBinder; // NEW LINE | ||
import static io.airlift.jaxrs.JaxrsBinder.jaxrsBinder; | ||
|
||
public class ServiceModule | ||
implements Module | ||
{ | ||
@Override | ||
public void configure(Binder binder) | ||
{ | ||
jaxrsBinder(binder).bind(ServiceResource.class); | ||
configBinder(binder).bindConfig(ServiceConfig.class); // NEW LINE | ||
} | ||
} | ||
``` | ||
|
||
### Step 4 - Use the Config Object | ||
|
||
Modify the Service resource to use the config object. Edit `ServiceResource.java` to look like this: | ||
|
||
```java | ||
package example; | ||
|
||
import javax.inject.Inject; // NEW | ||
import javax.ws.rs.GET; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.Produces; | ||
import javax.ws.rs.core.MediaType; | ||
|
||
@Path("/v1/service") | ||
public class ServiceResource | ||
{ | ||
private final ServiceConfig config; // NEW | ||
|
||
@Inject // NEW | ||
public ServiceResource(ServiceConfig config) // NEW | ||
{ // NEW | ||
this.config = config; // NEW | ||
} // NEW | ||
|
||
@GET | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public String hello() | ||
{ | ||
return config.getHelloMessage(); // CHANGED | ||
} | ||
} | ||
``` | ||
|
||
### Step 5 - Test The Change | ||
|
||
Build, run, test: | ||
|
||
``` | ||
mvn clean verify | ||
mvn exec:java -Dexec.mainClass=example.Service -Dnode.environment=test | ||
``` | ||
|
||
_In a different terminal_ : `curl http://localhost:8080/v1/service` | ||
|
||
Then CTRL+C the service. | ||
|
||
----- | ||
|
||
We assign a default value to `helloMessage` in `ServiceConfig` so Airlift uses that by default. Now | ||
let's run specifying a different value on the command line. | ||
|
||
``` | ||
mvn exec:java -Dexec.mainClass=example.Service -Dnode.environment=test -Dhello.message=Changed | ||
``` | ||
|
||
_In a different terminal_ : `curl http://localhost:8080/v1/service` | ||
|
||
Then CTRL+C the service. | ||
|
||
### Step 6 - Config File | ||
|
||
While it's simple to pass configuration on the command line, for production you will use a configuration | ||
properties file. Airlift configuration supports standard field=value property files. | ||
|
||
Create `config.properties` in the root of your project with the following content: | ||
|
||
```java | ||
node.environment=test | ||
hello.message=Hello from a config file! | ||
``` | ||
|
||
Now run and tell Airlift where to find the configuration file: | ||
|
||
```java | ||
mvn exec:java -Dexec.mainClass=example.Service -Dconfig=config.properties | ||
``` | ||
|
||
_In a different terminal_ : `curl http://localhost:8080/v1/service` | ||
|
||
Then CTRL+C the service. | ||
|
||
## Next Steps | ||
|
||
Return to [Next Steps](next_steps.md) to learn about other Airlift features. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
[◀︎ Airlift](../README.md) • [◀︎ Getting Started](getting_started.md) • [◀︎ Next Steps](next_steps.md) | ||
|
||
## Add Logging | ||
|
||
Airlift includes a simple logging API based on the JDK logging package. | ||
|
||
### Step 1 - Add Needed Dependencies | ||
|
||
We need a few additional dependencies. Add the following to the dependencies section of your | ||
`pom.xml` file: | ||
|
||
```xml | ||
<dependency> | ||
<groupId>io.airlift</groupId> | ||
<artifactId>log</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.airlift</groupId> | ||
<artifactId>log-manager</artifactId> | ||
</dependency> | ||
``` | ||
|
||
### Step 2 - Start Logging | ||
|
||
Example logging: | ||
|
||
```java | ||
import io.airlift.log.Logger; | ||
|
||
public class MyClass | ||
{ | ||
private static final Logger LOG = Logger.get(MyClass.class); | ||
|
||
public void fooBar(String argument) | ||
{ | ||
LOG.info("Formatted output %s", argument); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
[◀︎ Airlift](../README.md) • [◀︎ Getting Started](getting_started.md) • [◀︎ Next Steps](next_steps.md) | ||
|
||
## Add Metrics | ||
|
||
Airlift incorporates the [jmxutils](https://github.com/martint/jmxutils) library. Exposing | ||
JMX metrics is very simple. | ||
|
||
### Step 1 - Add Needed Dependencies | ||
|
||
We need a few additional dependencies. Add the following to the dependencies section of your | ||
`pom.xml` file: | ||
|
||
```xml | ||
<dependency> | ||
<groupId>org.weakref</groupId> | ||
<artifactId>jmxutils</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.airlift</groupId> | ||
<artifactId>jmx</artifactId> | ||
</dependency> | ||
``` | ||
|
||
### Step 2 - Add the JMX Modules | ||
|
||
Edit `Service.java` to look like this: | ||
|
||
```java | ||
package example; | ||
|
||
import io.airlift.bootstrap.Bootstrap; | ||
import io.airlift.event.client.EventModule; | ||
import io.airlift.http.server.HttpServerModule; | ||
import io.airlift.jaxrs.JaxrsModule; | ||
import io.airlift.jmx.JmxHttpModule; // NEW | ||
import io.airlift.jmx.JmxModule; // NEW | ||
import io.airlift.jmx.http.rpc.JmxHttpRpcModule; // NEW | ||
import io.airlift.json.JsonModule; | ||
import io.airlift.node.NodeModule; | ||
import org.weakref.jmx.guice.MBeanModule; // NEW | ||
|
||
public class Service | ||
{ | ||
public static void main(String[] args) | ||
{ | ||
Bootstrap app = new Bootstrap(new ServiceModule(), | ||
new JmxModule(), // NEW | ||
new JmxHttpModule(), // NEW | ||
new JmxHttpRpcModule(), // NEW | ||
new MBeanModule(), // NEW | ||
new NodeModule(), | ||
new HttpServerModule(), | ||
new EventModule(), | ||
new JsonModule(), | ||
new JaxrsModule()); | ||
app.strictConfig().initialize(); | ||
} | ||
|
||
private Service() {} | ||
} | ||
``` | ||
|
||
### Step 3 - Expose Some Metrics | ||
|
||
Let's add a counter to our REST endpoint. Modify `ServiceResource.java` to look like this: | ||
|
||
```java | ||
package example; | ||
|
||
import org.weakref.jmx.Managed; // NEW | ||
|
||
import javax.inject.Inject; | ||
import javax.ws.rs.GET; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.Produces; | ||
import javax.ws.rs.core.MediaType; | ||
|
||
import java.util.concurrent.atomic.AtomicLong; // NEW | ||
|
||
@Path("/v1/service") | ||
public class ServiceResource | ||
{ | ||
private final ServiceConfig config; | ||
private final AtomicLong helloCount = new AtomicLong(); // NEW | ||
|
||
@Inject | ||
public ServiceResource(ServiceConfig config) | ||
{ | ||
this.config = config; | ||
} | ||
|
||
@GET | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public String hello() | ||
{ | ||
helloCount.incrementAndGet(); // NEW | ||
return config.getHelloMessage(); | ||
} | ||
|
||
@Managed // NEW | ||
public long getHelloCount() // NEW | ||
{ | ||
return helloCount.get(); // NEW | ||
} | ||
} | ||
``` | ||
|
||
### Step 4 - Bind for JMX | ||
|
||
Expose the JMX value by binding it. Edit `ServiceModule.java` to look like this: | ||
|
||
```java | ||
package example; | ||
|
||
import com.google.inject.Binder; | ||
import com.google.inject.Module; | ||
|
||
import static io.airlift.configuration.ConfigBinder.configBinder; | ||
import static io.airlift.jaxrs.JaxrsBinder.jaxrsBinder; | ||
import static org.weakref.jmx.guice.ExportBinder.newExporter; // NEW | ||
|
||
public class ServiceModule | ||
implements Module | ||
{ | ||
@Override | ||
public void configure(Binder binder) | ||
{ | ||
jaxrsBinder(binder).bind(ServiceResource.class); | ||
configBinder(binder).bindConfig(ServiceConfig.class); | ||
newExporter(binder).export(ServiceResource.class).withGeneratedName(); // NEW | ||
} | ||
} | ||
``` | ||
|
||
### Step 5 - Test The Change | ||
|
||
Build, run, test: | ||
|
||
``` | ||
mvn clean verify | ||
mvn exec:java -Dexec.mainClass=example.Service -Dnode.environment=test | ||
``` | ||
|
||
Open `jconsole` or your preferred JMX tool and locate the "example" MBean. You will see the count | ||
increment for each time you `curl http://localhost:8080/v1/service`. |
Oops, something went wrong.