使用OpenTelemetry的自訂檢測 custom-instrumentation
為您的環境啟用OpenTelemetry時,AEM as a Cloud Service會追蹤每個要求並自動匯出JVM、HTTP和AEM量度。 該遙測描述了AEM。 它會顯示頁面花費900毫秒來呈現,以及呈現的元件。 它無法顯示您自己的程式碼正在做什麼,例如存放庫查詢是用於哪個清單專案,以及它是否找到任何內容,或是哪些頁面會因作者遺漏欄位而回覆為昂貴的搜尋。
您可以使用OpenTelemetry API自行新增該知識。 程式碼建立的範圍和屬性會透過自動遙測傳輸:相同的服務名稱、相同的處理、相同的APM提供者。 您不需要在程式碼中設定端點、認證或匯出工具。
如果您剛開始使用AEM as a Cloud Service上的OpenTelemetry,請從教學課程透過OpenTelemetry的可觀察性開始,瞭解其運作方式。 然後依照設定OpenTelemetry以深入分析AEM應用程式為您的環境啟用它。
此頁面上的範例檢測WKND參考網站。 每個範例都說明您想要達成的目的、要新增的程式碼,以及您可以在APM提供者中預期的結果。 完整的檢測程式碼(包括宣告於跨區上的單元測試)位於WKND存放庫的tutorial/otel-custom-instrumentation分支上。
自訂檢測如何運作 how-it-works
- Adobe在您的AEM環境中執行的OpenTelemetry Java代理程式包含OpenTelemetry SDK和匯出工具。 您的程式碼僅依賴OpenTelemetry API。
- 當您的程式碼呼叫
GlobalOpenTelemetry時,代理程式會將其連線到自己的實作。 您的範圍會成為執行範圍之要求追蹤的一部分,而您的遙測會隨環境遙測的其餘部分匯出。 - 當代理程式不存在時(本機AEM SDK、單元測試或環境未啟用OpenTelemetry),API不會執行任何動作,成本極低。 您可以將相同的程式碼部署到每個環境。
Tracer或@WithSpan註解Span APIWARN層級以上啟用記錄時設定您的專案 set-up-project
步驟1:新增OpenTelemetry API add-api
將OpenTelemetry API和檢測註解新增至專案上層pom.xml的dependencyManagement區段(範圍為provided):
<properties>
<opentelemetry.version>1.61.0</opentelemetry.version>
<opentelemetry-instrumentation.version>2.27.0</opentelemetry-instrumentation.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>${opentelemetry.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
<version>${opentelemetry-instrumentation.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
然後將兩個相依性(不含版本)新增至使用它們的每個套件組合的pom.xml,例如core/pom.xml:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
</dependency>
使用opentelemetry-api 1.61.0和opentelemetry-instrumentation-annotations 2.27.0或更早版本。 它們與AEM as a Cloud Service執行的OpenTelemetry Java代理程式相符,而且較新版本的代理程式會繼續支援它們。 在代理程式支援的版本之後新增的API功能沒有作用。
步驟2:將API內嵌於您的套件組合中 embed-api
AEM as a Cloud Service不會匯出OpenTelemetry API套件,因此使用該API的每個套件組合都必須包含自己的復本。 將下列指示新增至套件組合的bnd設定。 使用AEM專案原型,這就是core/pom.xml中的bnd-maven-plugin設定。 保留您的Import-Package指示已有的任何專案。
Import-Package: !io.opentelemetry.*,javax.annotation;version=0.0.0,*
-includepackage: io.opentelemetry.*
Import-Package開頭的!io.opentelemetry.*-includepackage: io.opentelemetry.*-conditionalpackage),則會捨棄您的範圍與屬性,而不會發生錯誤。每個使用API的套件都內嵌其自己的復本,而代理程式會個別連線每個復本。
OpenTelemetrySdk執行個體或呼叫GlobalOpenTelemetry.set()。 以這種方式傳送的遙測會略過代理程式、移除所傳送的資料中描述的Cloud Service基礎結構詳細資料,以及您設定的端點。步驟3:建立追蹤器 create-tracer
為您的程式碼基底建立一個Tracer,並在任何地方重複使用。 在WKND中,有一個小類別儲存它:
package com.adobe.aem.guides.wknd.core.telemetry;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
public final class WkndTelemetry {
/** Instrumentation scope: identifies telemetry produced by WKND code in your APM provider. */
public static final String SCOPE = "com.adobe.aem.guides.wknd";
public static final Tracer TRACER = GlobalOpenTelemetry.getTracer(SCOPE);
private WkndTelemetry() {
}
}
範圍名稱會出現在您透過此追蹤器建立的每個範圍上,作為檢測範圍(或程式庫名稱)。 使用可識別程式碼的名稱,例如專案的基本Java套件。
您的範圍顯示位置 where-spans-appear
在AEM as a Cloud Service上,頁面請求已經從AEM本身產生範圍。 程式碼建立的範圍會新增到其中。 例如,這是WKND Magazine頁面追蹤中「影像清單」元件的路徑:
GET /* the request (AEM)
└─ SlingMainServlet.service Sling request processing (AEM)
└─ AEM component: cq:Page (AEM)
└─ AEM component: wknd/components/page the page component (AEM)
└─ HTL: libs.core.wcm.components.page.v3.page.page__002e__html
└─ ... containers and layout grids (AEM)
└─ AEM component: wknd/components/image-list
└─ HTL: apps.wknd.components.image__002d__list.image__002d__list__002e__html
└─ ... spans that the Image List's Sling Model creates
在元件轉譯時,其HTL指令碼的範圍就是目前的範圍。 指令碼載入且包含data-sly-use的Sling模型在該範圍內執行,因此跨度以致模型建立的範圍會成為其子系。
每個要求範圍都命名為GET /* (或POST /*,以此類推)。 若要尋找特定頁面的追蹤,請搜尋請求範圍的url.path屬性,或新增您自己的屬性,如範例3所示。
範例 examples
範例1:追蹤昂貴的作業 trace-operation
您想要達成的目標 trace-operation-goal
WKND影像清單元件(wknd/components/image-list)會顯示頁面清單,每個頁面都有其第一個影像。 若要尋找該影像,其Sling模型ImageListImpl會針對清單中的每個專案執行一個QueryBuilder查詢。 AEM自己的範圍已顯示這些查詢:在列出五篇文章的WKND Magazine頁面上,追蹤在影像清單的HTL範圍下包含五個JCR query範圍。 它們不會顯示每個查詢針對的清單專案、是否找到影像或處理結果所花費的時間。 原始程式碼使用System.currentTimeMillis()將查詢計時,並將結果寫入DEBUG記錄專案,這在生產中無法使用。 您希望每個查詢在追蹤中以已命名作業的形式出現,並包含該內容。
程式碼 trace-operation-code
在ImageListImpl.findPageComponentResources()中,建立查詢周圍的範圍:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;
// ... build the QueryBuilder parameters, as before
final Span span = WkndTelemetry.TRACER.spanBuilder("ImageList.findPageComponentResources")
.setAttribute("wknd.query.path", page.getContentResource().getPath())
.setAttribute("wknd.query.resource_type", slingResourceType)
.setAttribute("wknd.query.limit", limit)
.startSpan();
try (Scope ignored = span.makeCurrent()) {
// ... run the query and collect the resources, as before
span.setAttribute("wknd.query.result_count", componentResources.size());
} catch (RuntimeException e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, "Image List query failed");
throw e;
} finally {
span.end();
}
return componentResources;
makeCurrent()將您的範圍設定為區塊內執行之所有專案的父系,包括AEM為存放庫查詢建立的範圍。- 一律呼叫
finally區塊中的end()。 不會匯出未結束的範圍。 - 為範圍指定描述操作的固定名稱,並將不同的值(例如路徑)放入屬性中。
結果 trace-operation-outcome
在列出五篇文章的WKND Magazine頁面上,追蹤現在在影像清單中包含五個ImageList.findPageComponentResources範圍,每個清單專案一個。 每一個都是AEM為其查詢建立的JCR query範圍的父系:
AEM component: wknd/components/image-list
└─ HTL: apps.wknd.components.image__002d__list.image__002d__list__002e__html
├─ ImageList.findPageComponentResources your span
│ └─ JCR query AEM
├─ ImageList.findPageComponentResources
│ └─ JCR query
└─ ... three more
您的每個範圍都有檢測範圍com.adobe.aem.guides.wknd和下列屬性:
wknd.query.path/content/wknd/us/en/magazine/arctic-surfing/jcr:contentwknd.query.resource_typewknd/components/imagewknd.query.limit1wknd.query.result_count1您現在可以針對每個清單專案,檢視查詢所搜尋的頁面、是否找到影像(wknd.query.result_count是0,但並未找到),以及整個查詢所花費的時間(包括處理結果)。 在WKND Magazine頁面上,每個查詢大約需要6.5毫秒,其中存放庫查詢本身大約需要3.5毫秒:一半的時間會用於處理結果,而AEM自己的範圍不會顯示這些結果。 由於查詢計數會隨著清單的長度而增加,因此您也可以檢視查閱佔用的元件轉譯時間量。
範例2:使用註解追蹤方法 with-span
您想要達成的目標 with-span-goal
WKND的SocialImageImpl模型會在每個頁面上執行,以填入og:image中繼標籤。 如果作者尚未設定精選影像,模型會逐步瀏覽頁面的內容樹狀結構以尋找第一個影像,並造訪最多500個資源。 您想要瞭解該步驟執行的頻率,以及它瀏覽的樹狀結構比例,而不需要重新建構方法。
程式碼 with-span-code
使用@WithSpan附註方法:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.instrumentation.annotations.WithSpan;
@WithSpan("SocialImage.resolveFromFirstImageOnPage")
protected boolean resolveFromFirstImageOnPage() {
Resource contentResource = currentPage.getContentResource();
if (contentResource == null) {
return false;
}
int[] visitedCount = new int[]{0};
Resource firstImage = findFirstImage(contentResource, 0, visitedCount);
// Span.current() is the span that @WithSpan started for this method.
Span.current().setAttribute("wknd.social_image.nodes_visited", visitedCount[0]);
Span.current().setAttribute("wknd.social_image.walk_truncated", visitedCount[0] > MAX_NODES_TO_VISIT);
// ... use firstImage, as before
}
- 代理程式會在每次方法執行時啟動範圍,並在方法傳回或擲回例外狀況時結束範圍。
@WithSpan使用公用、受保護及私用方法。- 若要將方法引數記錄為屬性,請以
@SpanAttribute標註引數,例如void applyTemplate(@SpanAttribute("wknd.page.template") String template)。 - 註解只有在代理程式執行時才會生效。 在本機AEM SDK和單元測試中,方法會以不變方式執行。
結果 with-span-outcome
SocialImage.resolveFromFirstImageOnPage範圍只出現在沒有精選影像的頁面的追蹤中:
wknd.social_image.nodes_visited21wknd.social_image.walk_truncatedfalsecode.namespacecom.adobe.aem.guides.wknd.core.models.impl.SocialImageImpl (由代理程式新增)code.functionresolveFromFirstImageOnPage (由代理程式新增)搜尋此範圍名稱可列出需要精選影像的頁面。 如果wknd.social_image.walk_truncated是true,則徒步停止在500個資源,且頁面可能完全沒有社交影像。
由@WithSpan建立的範圍包含代理程式的檢測範圍(io.opentelemetry.opentelemetry-instrumentation-annotations-1.16),而不是您的範圍。
範例3:將業務內容新增至目前範圍 current-span
您想要達成的目標 current-span-goal
您想要透過程式碼知道頁面社交影像來自的事實來篩選追蹤,而不需要建立另一個範圍。
程式碼 current-span-code
在SocialImageImpl中,將屬性新增至已啟用的範圍:
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.Span;
private static final AttributeKey<String> IMAGE_SOURCE = AttributeKey.stringKey("wknd.social_image.source");
@PostConstruct
protected void init() {
if (currentPage == null) {
return;
}
final String source;
if (resolveFromFeaturedImage()) {
source = "featured_image";
} else if (resolveFromFirstImageOnPage()) {
source = "first_image_on_page";
} else {
source = "none";
}
Span.current().setAttribute(IMAGE_SOURCE, source);
}
Span.current()會傳回最內層的使用中範圍,無論AEM或您建立的程式碼為何。 對於從HTL載入的Sling模型,這是載入模型的HTL指令碼範圍。- 如果沒有作用中的範圍,呼叫不會執行任何動作。
- 定義
AttributeKey常數可讓屬性名稱在程式碼中保持一致。
結果 current-span-outcome
頁面的customheaderlibs.html指令碼範圍(WKND在此指令碼中載入此模型)攜帶wknd.social_image.source,其值為featured_image、first_image_on_page或none。 搜尋wknd.social_image.source為none的追蹤以尋找沒有社交影像的已發佈頁面。
在WKND網站上,每個頁面都會報告first_image_on_page或none:沒有任何頁面會設定精選影像,因此每個頁面都會支付從範例2開始的內容樹狀結構瀏覽的費用。 在造訪次數最多的頁面上設定精選影像,會移除正常運作的專案。
範例4:記錄錯誤 record-errors
您想要達成的目標 record-errors-goal
WKND的ContentAIAvailabilityImpl模型會透過讀取OSGi設定來檢查內容AI 搜尋是否已設定。 如果查詢失敗,模型會將Content AI視為未設定並記錄警告。 頁面仍會呈現,且請求成功,因此很容易遺漏失敗。 您想要失敗顯示在APM提供者的錯誤檢視中,附加到失敗的作業。
程式碼 record-errors-code
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;
private boolean resolveConfigured() {
if (configurationAdmin == null) {
return false;
}
final Span span = WkndTelemetry.TRACER.spanBuilder("ContentAIAvailability.resolveConfigured").startSpan();
// Close the scope in finally, not with try-with-resources: try-with-resources closes it before
// the catch block runs, and the warning logged there must carry this span's trace and span IDs.
final Scope scope = span.makeCurrent();
try {
Configuration configuration = lookupConfiguration();
// ... read the API key, as before
span.setAttribute("wknd.content_ai.configured", isConfigured);
return isConfigured;
} catch (IOException e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, "Content AI configuration lookup failed");
LOGGER.warn("Unable to determine whether Content AI is configured (PID {})", CONTENT_AI_CLIENT_PID, e);
return false;
} finally {
scope.close();
span.end();
}
}
recordException()將exception事件新增至span,並包含例外狀況的型別、訊息及棧疊追蹤。setStatus(StatusCode.ERROR, ...)將範圍標籤為失敗。 在代表失敗作業的範圍上設定它。 請求本身不會標籤為失敗,因為元件已復原且頁面已轉譯。
結果 record-errors-outcome
追蹤包含狀態為 錯誤 且描述為Content AI configuration lookup failed的ContentAIAvailability.resolveConfigured範圍。 範圍有exception個事件:
exception.typejava.io.IOExceptionexception.messageConfiguration store unavailableexception.stacktrace範圍在您的APM提供者中計為錯誤,因此無論您的提供者顯示失敗作業,它都會顯示。 請求範圍會保持其狀態,因為請求傳回HTTP 200。
範例5:將記錄檔與追蹤建立關聯 correlate-logs
您想要達成的目標 correlate-logs-goal
當範例4中的Content AI查詢失敗時,您想要從記錄檔中的警告移至產生該警告的請求追蹤,然後再返回。
程式碼 correlate-logs-code
您不需要任何OpenTelemetry程式碼。 照常使用SLF4J進行記錄,並在OpenTelemetry設定中啟用記錄(logs: true):
LOGGER.warn("Unable to determine whether Content AI is configured (PID {})", CONTENT_AI_CLIENT_PID, e);
代理程式會將目前範圍的追蹤和範圍ID新增至每個記錄專案。 因為ContentAIAvailabilityImpl會記錄其從範例4跨越的時程,而且是最新的,所以警告會連結到該範圍。
結果 correlate-logs-outcome
您的APM提供者會收到如以下的記錄專案,並可顯示其追蹤:
WARNUnable to determine whether Content AI is configured (PID com.adobe.cq.wcm.core.components.internal.services.contentai.ContentAIClientImpl)ContentAIAvailability.resolveConfigured範圍的識別碼exception.type, exception.message, exception.stacktracecom.adobe.aem.guides.wknd.core.models.impl.contentai.ContentAIAvailabilityImplWARN層級及以上的記錄專案。 INFO和DEBUG專案不是。 請勿依賴這些資訊進行生產診斷:請將該資訊記錄為Span屬性。最佳實務 best-practices
- 名稱在作業之後延伸,而非資料。 使用名稱(例如
ImageList.findPageComponentResources),並將不同的值(例如路徑和ID)放入屬性中。 - 為您自己的屬性名稱加上專案的名稱空間,例如
wknd.。 這可避免與OpenTelemetry語意慣例和AEM使用的名稱衝突。 請勿使用保留給AEM的aem.首碼。 - 請勿在Span名稱、屬性、事件或記錄訊息中記錄個人資料或秘密。 這包括名稱、電子郵件地址、IP位址、權杖,以及可包含這些專案的查詢字串。
- 新增作業範圍,而非反複專案。 例如,範例2會為內容樹狀結構步驟建立一個範圍,並將瀏覽的資源數目記錄為屬性,而不是為每個資源建立一個範圍。 AEM已經為單一頁面建立了許多跨頁(WKND Magazine頁面約為260個),每個跨頁都會增加您的APM提供者所擷取的磁碟區。
- 建立追蹤器一次,並重複使用。
- 在
finally區塊中結束每個span,並在開啟它的執行緒上每隔Scope關閉一次。 - 將內容傳遞給您自己啟動的執行緒, (例如
Context.current().wrap(runnable)),以便在另一個執行緒上完成的工作會加入相同的追蹤。 - 要求以外的工作需要新的追蹤。 在Sling工作、排程工作或事件接聽程式中執行的程式碼沒有請求範圍。 您建立的範圍會開始自己的追蹤,每個回合各一個。
測試您的檢測工具 test
- 單元測試:若沒有代理程式,API將不會執行任何動作,因此您現有的單元測試會保持傳遞不變。
- 組建:在本機執行
mvn clean install。 Cloud Manager也會執行的AEM分析器會檢查您的套件組合匯入是否可解析。 - 套件組合內容:如步驟2所述,檢查您的套件組合是否包含完整的API。 例如,
unzip -l core/target/<your-core-bundle>.jar | grep "io/opentelemetry/api/baggage/"必須列出類別,而組合的META-INF/MANIFEST.MF不可匯入任何io.opentelemetry封裝。 - 您的APM提供者:部署至已啟用OpenTelemetry的開發環境、要求執行程式碼的頁面,以及搜尋您的APM提供者,以尋找您的跨區名稱或您在步驟3中選擇的檢測範圍。
疑難排解 troubleshooting
[api-regions-exportsimports] ... is importing package(s) [io.opentelemetry.api.incubator, io.opentelemetry.api.incubator.internal, io.opentelemetry.sdk.autoconfigure] in start level 20 but no bundle is exporting these for that start level.missing requirement ... osgi.wiring.package=io.opentelemetry.api.incubator。@WithSpan範圍會出現,但您的其他範圍以及您使用Span.current()設定的屬性不會出現。-includepackage: io.opentelemetry.*。 請參閱步驟2。Context.current().wrap(runnable)。WARN層級以上的專案,而且只有在您的設定中啟用記錄時才傳送。相關的文章 related-articles
- OpenTelemetry
- 記錄
- OpenTelemetry Java API (opentelemetry.io)
- OpenTelemetry Java代理程式的註解 (opentelemetry.io)
- OpenTelemetry語意慣例 (opentelemetry.io)
- WKND參考網站 (GitHub)
- WKND自訂檢測分支 (GitHub)