Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,5 @@ package-lock.json

# JavaScript bundler folder
out/
*.tgz
*.tgz
MinimalQuickstarts/python-django/db.sqlite3
42 changes: 42 additions & 0 deletions MinimalQuickstarts/aspnet_app_insights.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ASP.NET

## Setup Azure Monitor/App Insights

[Setup Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core) to instrument telemetry into your application.

```dotnet
builder.Services.AddApplicationInsightsTelemetry();
```

## Setup App Configuration

[Connect your application to App Configuration](https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-aspnet-core-app?tabs=entra-id), which supplies feature flags and other configurations to your application.
```dotnet
builder.Configuration.AddAzureAppConfiguration(options =>
{
options.Connect(new Uri(endpoint), new DefaultAzureCredential());
});
```

## Setup Feature Management

Add Feature Management to the service collection and add the targeting middleware. [Learn More](https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-feature-flag-aspnet-core#use-a-feature-flag)

```dotnet
builder.Services.AddFeatureManagement()
.WithTargeting()
.AddApplicationInsightsTelemetry();

app.UseMiddleware<TargetingHttpContextMiddleware>();
```

## Use Feature Management

Use DI to retrieve the FeatureManager, and get the assigned variant of the feature flag for the user. Use DI to get an instance of `FeatureManager` for flag data and `TelemetryClient` for custom events.

```dotnet
Variant variant = await _featureManager
.GetVariantAsync("MyFeatureFlag", HttpContext.RequestAborted);

telemetryClient.TrackEvent("checkout");
```
77 changes: 77 additions & 0 deletions MinimalQuickstarts/python-django/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Sample Python Django Application using Azure App Configuration

This is the sample Django application that uses the Azure App Configuration Service [Deploy a Python (Django or Flask) web app to Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/quickstart-python). For instructions on how to create the Azure resources and deploy the application to Azure, refer to the Quickstart article.

A [sample Flask application](../python-flask-webapp-sample/) is also available.

If you need an Azure account, you can [create one for free](https://azure.microsoft.com/en-us/free/).

## Prerequisites

You must have an [Azure subscription][azure_sub], and a [Configuration Store][configuration_store] to use this package.

To create a Configuration Store, you can either use [Azure Portal](https://ms.portal.azure.com/#create/Microsoft.Azconfig) or if you are using [Azure CLI][azure_cli] you can simply run the following snippet in your console:

```Powershell
az appconfig create --name <config-store-name> --resource-group <resource-group-name> --location eastus
```

### Create Keys

```Powershell
az appconfig kv set --name <config-store-name> --key testapp_settings_message --value "Hello from Azure App Configuration"
az appconfig feature set --name <config-store-name> --feature Beta
```

## Setup

Install the Azure App Configuration Provider client library for Python and other dependencies with pip:

```commandline
pip install -r requirements.txt
```

Set your App Configuration store endpoint as an environment variable.

### Command Prompt

```commandline
setx AZURE_APPCONFIG_ENDPOINT "your-store-endpoint"
```

### PowerShell

```Powershell
$Env:AZURE_APPCONFIG_ENDPOINT="your-store-endpoint"
```

### Linux/ MacOS

```Bash
export AZURE_APPCONFIG_ENDPOINT="your-store-enpoint"
```

Start the django application using the following command:
```commandline
# Run database migration
python manage.py migrate
# Run the app at http://127.0.0.1:8000
python manage.py runserver
```

## Refresh Configuration

To refresh your configuration, you first update the value in Azure App Configuration, then update the Sentinel value to trigger a refresh.

```Powershell
az appconfig feature enable --name <config-store-name> --feature Beta
```

Refresh the page in your browser to see the updated value.

NOTE: By default refresh can only be triggered every 30 seconds. You might have to wait up to 30 seconds and refresh the page again in order to see a change.

<!-- LINKS -->
[azure_sub]: https://azure.microsoft.com/free/
[azure_cli]: https://docs.microsoft.com/cli/azure
[configuration_store]: https://azure.microsoft.com/services/app-configuration/
16 changes: 16 additions & 0 deletions MinimalQuickstarts/python-django/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from django.core.management import execute_from_command_line
from opentelemetry.instrumentation.django import DjangoInstrumentor

def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quickstartproject.settings')
DjangoInstrumentor().instrument()
execute_from_command_line(sys.argv)


if __name__ == '__main__':
main()
Empty file.
7 changes: 7 additions & 0 deletions MinimalQuickstarts/python-django/quickstartproject/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quickstartproject.settings')

application = get_asgi_application()
17 changes: 17 additions & 0 deletions MinimalQuickstarts/python-django/quickstartproject/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from opentelemetry.baggage import set_baggage
from opentelemetry.context import attach
from opentelemetry.trace import get_current_span

class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
attach(set_baggage("Session-ID", request.session.session_key))
attach(set_baggage("Groups", ["Beta, Alpha"]))

get_current_span().set_attribute("TargetingId", request.session.session_key)

response = self.get_response(request)

return response
78 changes: 78 additions & 0 deletions MinimalQuickstarts/python-django/quickstartproject/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
from azure.appconfiguration.provider import load, WatchKey
from azure.identity import DefaultAzureCredential
from azure.monitor.opentelemetry import configure_azure_monitor
from featuremanagement import FeatureManager, TargetingContext
from featuremanagement.azuremonitor import TargetingSpanProcessor, publish_telemetry
from opentelemetry.baggage import get_baggage
from pathlib import Path

ALLOWED_HOSTS = []


def my_targeting_accessor() -> TargetingContext:
return TargetingContext(user_id=get_baggage("Session-ID"))

# Configure Azure Monitor
configure_azure_monitor(
connection_string=os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING"),
span_processors=[TargetingSpanProcessor(targeting_context_accessor=my_targeting_accessor)],
)

CONFIG = {}

ENDPOINT = os.environ.get("AZURE_APPCONFIG_ENDPOINT")

# Set up credentials and settings used in resolving key vault references.
credential = DefaultAzureCredential()

def callback():
global AZURE_APP_CONFIG
# Update Django settings with the app configuration key-values
CONFIG.update(AZURE_APP_CONFIG)

# Load app configuration key-values
AZURE_APP_CONFIG = load(
endpoint=ENDPOINT,
credential=credential,
refresh_on=[WatchKey("sentinel")],
feature_flag_enabled=True,
feature_flag_refresh_enabled=True,
on_refresh_success=callback,
)

FEATURE_MANAGER = FeatureManager(AZURE_APP_CONFIG, targeting_context_accessor=my_targeting_accessor, on_feature_evaluated=publish_telemetry)


# Updates the config object with the app configuration key-values and resolved key vault reference values.
# This will override any values in the config object with the same key.
CONFIG.update(AZURE_APP_CONFIG)

SECRET_KEY = "a"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ROOT_URLCONF = "quickstartproject.urls"

MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'quickstartproject.middleware.SimpleMiddleware',
]

INSTALLED_APPS = [
"django.contrib.sessions",
]


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}

18 changes: 18 additions & 0 deletions MinimalQuickstarts/python-django/quickstartproject/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.urls import path
from django.http import HttpResponse
from django.conf import settings
from opentelemetry.baggage import get_baggage
from featuremanagement.azuremonitor import track_event


async def index(request):
# Refresh the configuration from App Configuration service.
settings.AZURE_APP_CONFIG.refresh()
track_event("index", request.session.session_key)

return HttpResponse(str(settings.FEATURE_MANAGER.is_enabled("Beta")))


urlpatterns = [
path('', index, name='index'),
]
8 changes: 8 additions & 0 deletions MinimalQuickstarts/python-django/quickstartproject/wsgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import os

from django.core.wsgi import get_wsgi_application

settings_module = 'quickstartproject.settings'
os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)

application = get_wsgi_application()
4 changes: 4 additions & 0 deletions MinimalQuickstarts/python-django/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Django==4.2.16
azure-appconfiguration-provider==1.3.0
azure-identity==1.16.1
featuremanagement==1.0.0
65 changes: 65 additions & 0 deletions MinimalQuickstarts/python_flask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# ------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# -------------------------------------------------------------------------
import os
import uuid
from azure.appconfiguration.provider import load
from azure.identity import DefaultAzureCredential
from azure.monitor.opentelemetry import configure_azure_monitor
from featuremanagement import FeatureManager, TargetingContext
from featuremanagement.azuremonitor import TargetingSpanProcessor, track_event, publish_telemetry
from opentelemetry import trace
from opentelemetry.trace import get_tracer_provider
from opentelemetry.baggage import set_baggage, get_baggage

def my_targeting_accessor() -> TargetingContext:
session_id = get_baggage("Session-ID")
if not session_id:
session_id = str(uuid.uuid4())
set_baggage("Session-ID", session_id)
return TargetingContext(user_id=session_id)

# Configure Azure Monitor
configure_azure_monitor(
connection_string=os.getenv("APPLICATIONINSIGHTS_CONNECTION_STRING"),
span_processors=[TargetingSpanProcessor(targeting_context_accessor=my_targeting_accessor)],
)

tracer = trace.get_tracer(__name__, tracer_provider=get_tracer_provider())

from flask import Flask, make_response, session, request
from flask.sessions import SecureCookieSessionInterface

app = Flask(__name__)
app.session_interface = SecureCookieSessionInterface()
app.secret_key = os.urandom(24)

ENDPOINT = os.environ.get("AZURE_APPCONFIG_ENDPOINT")
credential = DefaultAzureCredential()

global azure_app_config, feature_manager
azure_app_config = load(
endpoint=ENDPOINT,
credential=credential,
feature_flag_enabled=True,
feature_flag_refresh_enabled=True,
)

feature_manager = FeatureManager(azure_app_config, targeting_context_accessor=my_targeting_accessor, on_feature_evaluated=publish_telemetry)
app.config.update(azure_app_config)

@app.route("/")
def index():
global azure_app_config
# Refresh the configuration from App Configuration service.
azure_app_config.refresh()
response = make_response(str(feature_manager.is_enabled("Beta")))
response.mimetype = "text/plain"
track_event("index", get_baggage("Session-ID"))

return response

if __name__ == "__main__":
app.run()
Loading