投稿者: sumito.tsukada

  • AWS X-Ray と X-Amzn-Trace-Id の深掘り

    AWS X-Ray と X-Amzn-Trace-Id の深掘り

    AWS X-Ray は、アプリケーションの動作を可視化し、ボトルネックや問題点を特定するためのサービスです。X-Ray のトレース機能をフル活用するためには、X-Amzn-Trace-Id ヘッダの正しいフォーマットと使用が不可欠です。この記事では、このヘッダのフォーマットと、それを正しく使用するためのヒントや注意点について解説します。

    1. X-Amzn-Trace-Id のフォーマット

    ヘッダは以下の構成要素からなります:

    • Root:トレースのユニークな識別子。例: 1-<8桁の16進数のエポックタイムスタンプ>-<24文字のランダム値>
    • Parent:呼び出し元のサービスのセグメントID(オプション)。
    • Sampled:トレースデータをX-Rayに送信するかどうかを示すフラグ。通常、0(送信しない)または1(送信する)のいずれかの値を持ちます。

    2. エポックタイムスタンプと16進数

    Root の部分には、エポックタイムスタンプの16進数表現が必要です。この値は、UNIX時間(1970年1月1日からの秒数)を16進数に変換したものです。これにはシェルスクリプトを使用して簡単に取得できます:

    hex_time=$(printf '%x' $(date +%s))

    3. X-Ray への正確なログ表示のための注意点

    • 時間の正確さX-Amzn-Trace-Id のタイムスタンプが正確でないと、X-Ray には表示されますが、期待した時刻の範囲で表示されない可能性があります。
    • 16進数の確認Root の3文字目は16進数でなければなりません。これを確認しないと、X-Ray はトレース情報を正しく処理できません。
    • トレースIDの生成:独自のアプリケーションやバッチ処理からリクエストを送る場合は、適切な X-Amzn-Trace-Id ヘッダを自分で生成する必要があります。

    4. サンプルのシェルスクリプト

    以下は、curl コマンドを使用して適切な X-Amzn-Trace-Id ヘッダを付与したリクエストを送るためのサンプルスクリプトです:

    bash
    #!/bin/bash

    # エポックタイムスタンプの16進数取得
    hex_time=$(printf '%x' $(date +%s))
    trace_id="Root=1-$hex_time-a5d9f372e21340000000000001;Sampled=1"

    # curl コマンド実行
    curl --location 'https://your-api-endpoint.com/path' \
    --header 'Content-Type: application/json' \
    --header "X-Amzn-Trace-Id: $trace_id" \
    --data 'YOUR_PAYLOAD_HERE'

    5. まとめ

    AWS X-Ray をフルに活用するためには、正確な X-Amzn-Trace-Id ヘッダの生成と送信が不可欠です。特に、エポックタイムスタンプの正確さや16進数のフォーマットが重要です。この記事の情報を使用して、X-Ray でのトレースデータの可視化を効果的に行うことができるでしょう。

  • Autifyでの高度な待機処理: 非活性ボタンを活性化するまで

    はじめに

    テストオートメーションツール「Autify」は、非技術者でも簡単にWebアプリケーションのE2Eテストを構築・実行することができるツールです。しかしながら、特定の操作が完了するまで待機するといったシチュエーションでは、JavaScriptステップを利用することでより高度な制御が可能になります。

    今回は、あるボタンが非活性(disabled)から活性になるのを待つシチュエーションを例に、Autify内でのJavaScriptステップの作成方法を解説します。

    シチュエーション

    テストシナリオ内で、あるアクションの後、ボタンが活性化されるのを30秒間待ち、活性になったらその後のステップへ進むというシチュエーションを想定します。

    解決方法

    Autify内でJavaScriptステップを作成し、以下のスクリプトを利用します。

    var xpath = "/html/body/div[1]/div/div/div/div[1]/div/div[3]/div[2]/button";
    var element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    if (!element) {
    throw new Error("Error: cannot find the element with xpath(" + xpath + ").");
    }
    var endTime = Date.now() + 30000;
    (function checkIfEnabled() {
    if (Date.now() > endTime) {
    throw new Error("Timeout: Button was not enabled within 30 seconds.");
    }
    if (!element.disabled) {
    return;
    } else {
    setTimeout(checkIfEnabled, 500);
    }
    })();

    まとめ

    Autifyは直感的なインターフェースでテストシナリオを組むことができますが、JavaScriptステップをうまく活用することで、さらに柔軟なテストの実現が可能となります。このようなテクニックを駆使して、品質の高いテストオートメーションを構築しましょう。

  • AWS SAM CLIでDockerがUnreachableな場合の解決

    AWS SAM CLIでDockerがUnreachableな場合の解決

    はじめに

    AWS Serverless Application Model (SAM) は、サーバレスアプリケーションを簡単に作成、テスト、デプロイするためのフレームワークです。しかし、時々 sam build --use-container コマンドを使用したときに、”Docker is unreachable. Docker needs to be running to build inside a container.”というエラーメッセージが表示されることがあります。

    Dockerが実行中であり、Dockerのバージョン情報が正しく表示されているにもかかわらず、このエラーが発生することがあります。このブログでは、その問題の解決法について説明します。

     

    問題の再現

    以下のようなコマンドを実行してみました。

    $ sam build --use-container

    そして、以下のエラーが表示されました。

    Error: Docker is unreachable. Docker needs to be running to build inside a container.

    しかし、Dockerは実行中であり、バージョン情報も正しく表示されます。

    $ docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

    $ docker --version
    Docker version 23.0.5, build bc4487a

    解決法

    解決法は、Dockerのコンテキストを確認し、適切に設定することです。

    まず、現在のDockerのコンテキストを表示します。

    $ docker context ls

    次に、適切なDockerのエンドポイントに対する環境変数 DOCKER_HOST を設定します。

    $ DOCKER_HOST=unix:///Users/sumito.tsukada/.docker/run/docker.sock sam build --use-container

    これにより、Dockerが適切に認識され、SAM buildコマンドが正常に実行されるはずです。

    結論

    DockerとAWS SAM CLIの連携は、サーバレスアプリケーションの開発をスムーズに進める上で非常に便利です。しかし、時々ツール間の接続に問題が生じることがあります。そのような場合は、環境変数を適切に設定し直すことで問題が解決することがあります。ぜひ、この記事があなたの問題解決の一助となることを願っています。

  • ターミナルを開いたら自動でtmuxを起動させる

    ターミナルを開いたら自動でtmuxを起動させる

    はじめに

    tmuxを起動させることを自動化して、新しいターミナルウィンドウを開くと同時にtmuxが起動するように設定する方法を紹介します。

    今回はmacOSのiTerm2を例に説明します。

    ステップバイステップのガイド

    ステップ1: iTerm2を開く

    まずはiTerm2を開きましょう。もしまだインストールしていない場合は、公式サイトからダウンロードしてインストールしてください。

    ステップ2: Preferencesを開く

    次に、上部メニューから「iTerm2」をクリックし、「Preferences」を選択します。またはキーボードショートカットのcommand+,を使用することもできます。

    ステップ3: プロファイル設定を開く

    「Profiles」タブをクリックしてください。左側のプロファイルリストから、使用したいプロファイル(「Default」を使用している方が多いと思います)を選択します。

    ステップ4: コマンド設定を行う

    「General」タブの「Command」セクションに進みます。「Send text at start」にtmuxと入力し、設定を保存します。

    これで設定は完了です。

    ステップ5: 新しいターミナルウィンドウを開く

    新しいターミナルウィンドウ(新しいタブや新しいウィンドウでも構いません)を開いてみましょう。自動的にtmuxが起動するはずです。

    まとめ

    この設定を行うことで、毎回手動でtmuxコマンドを打つ必要がなくなります。

    一度の設定でこれ以降の作業を効率化できるので、ぜひお試しください。

     

     

  • jqを使ったJSONデータの柔軟な操作: ユーザーの属性値の動的変更

    jqを使ったJSONデータの柔軟な操作: ユーザーの属性値の動的変更

    はじめに

    jqはコマンドラインツールで、JSONデータをパースしたり操作したりするのに非常に便利です。今回は、特定のユーザーの属性(タグリスト)から特定の要素を削除する、という具体的なタスクを通じて、jqの使い方について解説します。

    JSONデータの説明

    まずは問題を理解するために、私たちが操作するJSONデータを見てみましょう。以下のような形式のデータです:

    {
    "data": {
    "users": [
    {
    "username": "Alice",
    "tags": "tag1, tag2"
    },
    {
    "username": "Bob",
    "tags": "tag2"
    },
    {
    "username": "Charlie"
    }
    ]
    }
    }

    このデータは、”data”というキーの中に、”users”という配列があります。各ユーザーは”username”と”tags”という2つの属性を持つことができます。

    目標の説明

    ここでの目標は、特定のユーザー(この例では”Alice”)のタグリストから特定のタグ(この例では”tag2″)を削除することです。このようなタスクは、例えば特定のユーザーのロールや権限、ステータスなどを更新する際によく遭遇します。

    jqコマンドの解説

    目標を達成するために、以下のようなjqコマンドを使用します。

    jq -r --arg username "Alice" --arg delete_tag "tag2" '
    .data.users |= map(
    if .username == $username then
    if .tags? | contains($delete_tag) then
    if .tags == $delete_tag then
    del(.tags)
    else
    .tags |= gsub($delete_tag + ", "; "")
    | .tags |= gsub(", " + $delete_tag; "")
    end
    else
    .
    end
    else
    .
    end
    )
    '
    users.json

    ここで”-r”オプションは、出力結果をraw形式(エスケープされていない形式)で出力することを指定します。

    “–arg username “Alice”” と “–arg delete_tag “tag2″” では、コマンド実行時にjqに変数を渡しています。これにより、このコマンドは特定のユーザー名と削除するタグを動的に指定できます。

    そして、”.data.users |= map(…)”では、全てのユーザー(.data.usersの配列)を一つずつ処理しています。この”map”関数は、配列の全ての要素に対して指定した処理(ここでは後続のif文全体)を適用します。

     

    jqコマンドの詳細

    ここで、このjqコマンドがどのように動作しているのかを詳しく見ていきましょう。

    まず、”if .username == $username then”という行では、現在処理しているユーザーのusernameが指定したusernameと一致するかどうかを確認します。もし一致すれば、そのユーザーに対して更なる処理(後続のif文)を行います。

    次に、”if .tags? | contains($delete_tag) then”という行では、現在処理しているユーザーがtags属性を持ち、その中に削除するタグが含まれているかを確認します。ここで、”?”演算子を使うことで、もしユーザーがtags属性を持っていなければエラーにせずにnullを返します。

    そして、もしユーザーが削除するタグだけを持っている場合(つまり、そのユーザーのtagsが削除するタグと全く同じである場合)、”if .tags == $delete_tag then del(.tags)”という部分でそのtags全体を削除します。

    もしユーザーが削除するタグを含むが、他にもタグを持っている場合(つまり、そのユーザーのtagsが削除するタグを含むカンマ区切りの文字列である場合)、

    .tags |= gsub($delete_tag + ", "; "")
    | .tags |= gsub(", " + $delete_tag; "")

    という部分で削除するタグを取り除きます。ここで、”gsub”関数は、第一引数の正規表現にマッチする全ての部分を第二引数に置き換えます。つまり、この行では、タグリストから削除するタグを取り除いています。

    まとめ

    以上が、jqを使ってJSONデータを操作する具体的な例です。この例を通じて、jqの強力さと柔軟性を理解していただけたと思います。JSONデータを操作する必要がある場合、是非jqをお試しください。

  • FlaskとQueueを用いたタスク管理の実装

    FlaskとQueueを用いたタスク管理の実装

    PythonのFlaskフレームワークは、その軽量さと拡張性から、さまざまなウェブアプリケーションで用いられています。今回はFlaskを使用したシステムで、Pythonの組み込みモジュールであるQueueを利用して、タスク管理を効率的に行う方法について解説します。

    この記事で取り扱う主要なテーマは以下の通りです:

    • PythonのQueueを使ったタスク管理
    • Queueとスレッドを組み合わせた非同期処理

    PythonのQueueを使ったタスク管理

    Pythonのqueue モジュールは、FIFO(First-In, First-Out)方式のキューを実装しており、スレッド間でデータの受け渡しを行う際に特に有用です。以下に具体的なコードを示します。

    import queue
    import threading
    # グローバルにキューを作成
    task_queue = queue.Queue()
    def worker():
    while True:
    task = task_queue.get()
    if task is None:
    break
    # ここでタスクを処理
    task_queue.task_done()
    # ワーカースレッドを作成し、実行
    worker_thread = threading.Thread(target=worker)
    worker_thread.start()
    @app.route('/task', methods=['POST'])
    def add_task():
    task_data = request.get_json()
    task_queue.put(task_data)
    return jsonify({'status': 'queued'})

    このコードでは、新たなタスクがPOSTリクエストとして/taskエンドポイントに送信されると、そのタスクはキューに追加されます。一方、バックグラウンドで実行されているワーカースレッドは、キューからタスクを取り出して処理を行います。

    Queueとスレッドを組み合わせた非同期処理

    Queueとスレッドを組み合わせることで、Flaskアプリケーションでの非同期タスク管理を実現できます。これにより、リクエストを迅速に受け付けつつ、時間のかかる処理をバックグラウンドで並行して実行することができます。

    この記事が皆さんのFlaskとPythonのプロジェクトに役立つことを願っています

  • FlaskとThreadを使った並行処理と排他制御の実装

    FlaskとThreadを使った並行処理と排他制御の実装

    PythonのFlaskフレームワークは、小規模なアプリケーションから大規模なエンタープライズアプリケーションまで幅広い用途で使用されています。今回は、Flaskを用いたウェブアプリケーションで、複数のリクエストが同時に来た場合でも、裏側で動く処理を1つに制限する方法を解説します。

    この記事で取り扱う主要なテーマは以下の通りです:

    • Pythonのスレッドを使った並行処理
    • 排他制御によるリソースへの同時アクセス制限

    スレッドを使った並行処理

    Python の threadingモジュールを用いることで、スレッドを利用した並行処理を実装することができます。以下に具体的なコードを示します。

    import threading
    # スレッドを使う処理は関数にまとめます
    def process_request(request_data):
    # リクエストに対する処理を記述
    pass
    @app.route('/exec', methods=['POST'])
    def exec():
    # POSTリクエストのデータを取得
    request_data = request.get_json()
    # 新たなスレッドを作成して関数を実行
    thread = threading.Thread(target=process_request, args=(request_data,))
    thread.start()
    # レスポンスを即時に返す
    return jsonify({'status': 'processing'})

    このコードでは、POSTリクエストが/execエンドポイントに送信されると、新たなスレッドが作成され、process_request関数がそのスレッド上で実行されます。この関数はリクエストのデータを処理し、その間、メインスレッドは次のリクエストを受け付ける準備をします。

    排他制御による同時アクセス制限

    一方、裏側で動く処理を1つに保つためには排他制御が必要です。PythonのthreadingモジュールのLockを用いることで、排他制御を実現できます。以下に具体的なコードを示します。

    lock = threading.Lock()
    def process_request(request_data):
    with lock:
    # リクエストに対する処理を記述
    pass

    このコードでは、lockオブジェクトを用いてwithステートメントの中の処理が排他的に実行されるようになります。すなわち、一度に一つのスレッドだけがこの処理を実行でき、他のスレッドはロックが解放されるまで待機する必要があります。

    これらの方法を組み合わせることで、Flaskでの並行リクエストの受け付けと裏側での処理の排他制御を実現することができます。これにより、アプリケーションのパフォーマンスと安定性を向上させることが可能になります。

    この記事が皆様のPythonとFlaskのプロジェクトに役立つことを願っています。

  • PostgreSQLのテーブル定義を確認する方法:コマンドラインとGUIクライアントの違い

    PostgreSQLのテーブル定義を確認する方法:コマンドラインとGUIクライアントの違い

    PostgreSQLデータベースを操作する際、テーブルの定義を確認する必要がしばしばあります。

    テーブルの列名やデータ型を把握することで、適切なSQLクエリを作成し、データ操作を正確に行うことができます。

    一般的に、PostgreSQLのコマンドラインツールであるpsqlを使用してテーブルの定義を確認することが多いです。コマンドは、指定したテーブルの列名、データ型、修飾子、そして列の説明を表示します。

    例えば、テーブル名がhoge_tableの場合、次のコマンドを使用します:

    \d hoge_table

    しかしながら、全てのデータベース操作がコマンドラインから行われるわけではありません。

    GUIベースのデータベースクライアントツールを使用することが一般的であり、その中でもTablePlusはその使いやすさと直感的なインターフェースで高く評価されています。

    しかし、TablePlusやその他のいくつかのGUIクライアントツールでは、psql特有の\dコマンドが使用できません。

    その場合、次のSQLクエリを使用してテーブルの構造を確認することができます

    SELECT column_name, data_type
    FROM information_schema.columns
    WHERE table_name = 'hoge_table';

    このクエリは、テーブルのすべてのカラム名とそのデータ型を表示します。この方法は標準的なSQLクエリであるため、多くのデータベース管理ツールで使用できます。

    データベースを操作する際には、使用しているツールの特性を理解し、それに応じた最適な操作方法を選択することが重要です。それによって効率的かつ正確なデータ操作を行うことが可能となります。この記事がその一助となれば幸いです。

  • ターミナル操作の効率化:cdコマンドを使った直前のディレクトリへの素早い移動方法

    ターミナル操作の効率化:cdコマンドを使った直前のディレクトリへの素早い移動方法

    はじめに

    日々の開発作業でコマンドラインからファイルシステムを操作することは非常に一般的です。ディレクトリを行き来する際、完全なパスを何度も入力したり、タブ補完を使ってパスを探すのは時間の無駄ですよね。この記事では、ZshやBashなどのシェルで使える、直前のディレクトリに瞬時に戻る方法を紹介します。

    コマンドラインでのナビゲーションの効率化

    コマンドラインでの作業は速度と効率が重要です。頻繁にディレクトリを行き来する作業は、キーボード入力の手間だけでなく、思考の中断も引き起こします。そこで、直前のディレクトリに素早く戻る方法が必要です。

    cd - コマンド:直前のディレクトリに戻る

    このコマンドは、直前にいたディレクトリに素早く戻るためのコマンドです。これを使用すると、前回までにいたディレクトリに戻ることができます。以下にその使い方を示します。

    この一行のコマンドは、bashや他の多くのシェルでも同様に機能します。

    まとめ

    ターミナルでの作業をより効率的に進めるために、cd - のようなシンプルなコマンドが非常に役立ちます。頻繁にディレクトリを行き来する作業を行っている場合、このコマンドは手間を大幅に削減し、作業の効率を向上させることができます。

     

  • Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user. You can enable privileged port mapping from Docker -> Settings… -> Advanced -> Enable privileged port mapping

    Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user. You can enable privileged port mapping from Docker -> Settings… -> Advanced -> Enable privileged port mapping

     

     ports:
    - ${LOCAL_IP}:80:80
    - ${LOCAL_IP}:443:443

    docker-compose で上記のように 80, 443 のような 1023 番以下のport をマッピングさせようとしたところ、エラーになることがあります。

    Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user.
    You can enable privileged port mapping from Docker -> Settings... -> Advanced -> Enable privileged port mapping

    一般的にエラー文言に従い、Dockerの設定から “Enable privileged port mapping” を有効にしましたが、エラーが解消されない状況に陥りました。

    この問題に直面したとき、Dockerの設定でCLIツールのインストール方法を変更することで回避できました。

    具体的には、Dockerの設定の “Advanced” タブから “Choose how to configure the installation of Docker’s CLI tools” を開き、その設定を “User” から “System” に変更しました。

     

    この変更により、Dockerはシステムレベルで動作するようになり、これにより特権ポートを使用するための必要な権限を得ることができるようになるようです。

    結果として、ポート80と443が正常に割り当てられるようになり、エラーは解消しました。