検索機能追加!

検索機能が追加されました。右側のやつです。 実装方法 このブログページ自体は nuxt/contentで動いているため、nuxt/content の全文検索機能を用いて実装しました。全文検索自体はドキュメントを読めば簡単にできるので、content の良さを実感しています。 工夫点 もちろんタグ検索ですねー。元々ブログ記事にはタグを埋め込むようにしていたので、それで検索をかけています。タグの埋め込みイメージは下のような感じです。yml のため配列で格納するのも考えたのですが、こちらの形式の方が、全文検索のさいに扱いやすかったので、こちらで保存しています。 tags: Golang CloudRun 全てのタグ自体は、非同期に記事を全検索書けてマップでタグの値を数えて、DOM の値を更新するという風にしています。Vue では Map の変更が上手く反映されなかったので、このように最後に配列に push していくという形式を取っています。そんなに大量に記事が増えることもないと思うので、サーバーレンダリングでも良い気はしますが、一応非同期に行っています。手間がかかった割に地味な機能なんですよね。。。 const tags = reactive<TagCount[]>([]); onMounted(() => { context.root .$content(queryName) .only("tags") .fetch<Promise<{ tags: string }[]>>() .then((resps) => { const tagMap = new Map<string, number>(); resps.map((resp) => { _ = resp.tags?.split(" ").forEach((tag) => { tagMap.set(tag, (tagMap.get(tag) || 0) + 1); }); }); tagMap.forEach((num, tag) => { tags.push({ name: tag, count: num, }); }); }); }); はまったこと はまったことは、クエリが変わった際に発火するようにした asyncData の検索結果が、サーバーレンダリング時とクライント実行時で結果が変わったことです。...

2020/09/01(作成日) · 2022/09/26(更新日)

gitのディレクトリ情報保存方法

背景 git は差分管理ツールというイメージが強いですが、どうやってディレクトリ情報を保存しているかについてふと疑問に思いました。 ディレクトリ情報も差分で管理している?差分ならどこから適用している?.gitの中に実は入っている? 少し考えても手段は分からなかったので調べて見ました。 sha1(前提知識) 今回調べた結果として git で使用されている sha1 というハッシュ技術に触れないわけにはいかないので、前提知識として少し説明します。といっても大した内容じゃないですが… git では sha1 と呼ばれるハッシュ技術を使用しております。みなさんが git のハッシュと聞いて最初に思い浮かべるのは commit ハッシュだと思います。現在はこの sh1 はセキュリティ上の脆弱性などが見つかり sh2 系統が暗号化技術では主流になっています。まぁ、git の使い方では気にするようなものでもない気がしますが、どうなんですかね。面倒でよく調べていません。 まぁ、git の根幹とも言える技術であり、こういうハッシュ技術をいろんな所に使っているよっていうのが今回のオチだったりします。 どうやってディレクトリ情報を保存しているか それではどうやって保存しているかを見ていきます。 まず、以下のようにして適当なレポジトリをコピーして、ディレクトリ内に入ります。 $ git clone git@github.com:komem3/go-diary.git $ cd go-diary ログなどを確認して適当な commit ハッシュを取ってきます。 $ git log | grep commit | head -n3 commit 14bde74b0c41c5fa48313ea78185e77668b97f20 (HEAD -> master, origin/master, origin/HEAD) commit 352908fdb0ea4b5a9e611c060eeb496d61d248f4 commit b2175aadf10b51307c33d931840241d0d57bc7e5 この取得したコミットハッシュをデコードしていきます。git には ハッシュに関する操作を行うコマンドがあるため、そのコマンドを使用します。 以下のように入力するとコミットの内容が見れます。コミットハッシュはコミットの内容から作っているってことがよく分かります。 $ git cat-file -p 352908fdb0ea4b5a9e611c060eeb496d61d248f4 tree 30e8473323d6fc439711f2814cb433c7bb408e3b parent b2175aadf10b51307c33d931840241d0d57bc7e5 author dependabot[bot] <49699333+dependabot[bot]@users....

2020/08/24(作成日) · 2022/09/26(更新日)

nuxt+contentでsitemap生成

なぜ? nuxt の sitemap プラグインでは pages 配下のものは自動でパスとして登録してくれます。 しかし、pages/_id.vueやpages/_slug.vueのような動的にパスがきまるものは自動で登録することができません。そのため、content などを使用している場合は、自身んで登録する必要が出てきます。 方法 content の中身が増える度に自分で routes に登録してもいいと思いますが、プログラマーっぽくないので、関数を使っていきます。 今回僕は/blog/_slug.vueに対しての操作を行ったため、nuxt.config.js に以下のように記載しました。content の api で slug 取得して、配列で URL 返しているだけですねー。 sitemap: { hostname: 'https://mobtown.jp', gzip: true, routes: async () => { const { $content } = require('@nuxt/content'); const files = await $content('article').only(['slug']).fetch(); return files.map((f) => `/blog/${f.slug}`); }, }, 生成されたものは当然 https://mobtown.jp/sitemap.xml からみることができます。 感想 content の api が結構有能に感じました。 関係ないですが、wsl2 上の emacs で書いた記事だったので結構しんどかったです。

2020/08/17(作成日) · 2022/09/26(更新日)

zap + stackdriver logging + grpc on Cloud Run

目標 grpc 使用時に、zap の出力結果が stackdriver logging でまとまるようにしていきます。 cloud run での出力条件 Cloud run の標準出力はデフォルトで logging にエクスポートされます。しかし、特定の出力は特殊フィールドとみなされます。まずは、その特殊フィールドを見ていきます。 公式ドキュメントには以下のように記載されています。 When the Logging agent receives a structured log record, it treats the following fields specially, allowing you to set specific fields in the LogEntry object that get written to the Logging API. つまり、jsonなどで出力された際に、特定の名前のフィールドが特殊フィールドと扱われることが分かります。 一個ずつ特殊フィールドを見ても公式をなぞるだけなので、今回目指したい出力を以下に記します。 { "severity": "ログの重要度(例:DEBUG)", "message": "ログメッセージ", "time": "ログのタイムスタンプ", "logging.googleapis.com/trace": "トレースID(例:projects/[PROJECT-ID]/traces/[V])", "logging.googleapis.com/spanId": "同一トレース内のスパンID(例:000ddfff3)" } 上記のようなフィールドが特殊フィールドとみなされ、標準で出力されるリクエストのログに対してまとまってくれます。それではこれを目指して行きます。logging.googleapis.com/trace_sampled はopencensusなどのtraceライブラリの設定が必要なので、今回はやりません。 zap で出力する zap の設定 上記のように出力するために、zap の設定は以下のようにしました。今回はプラグインなどを使わず自力で実装しています。...

2020/08/12(作成日) · 2022/09/26(更新日)

fgprofについて

fgprof とは fgprofとは、go 言語のサンプリングプロファイルツールとなります。 プロファイルツールって何ぞやって人もいると思いますが、簡単にいうと「処理にかかった時間やメモリの使用量を測定するツール」といった感じになります。使用してみると下の図のように、処理に対して、どの関数がどのくらい時間がどのくらいかかったのかを、視覚的に見ることができます。(下の図は fgprof に記載されている pprof のサンプル図です。) gcp だと stack trace とかをイメージしてもらうのがいいですね。 そして、go 言語には、すでに pprof という公式のプロファイルツールが存在します。しかし、この pprof は on-cpu の処理のみ測定が行うわれます。on-cpu の処理というのはいわゆる cpu 上の計算のみです。このため、DB に対してのクエリ、他サービスへのアクセス、ディスク IO などの、cpu 上で行われない処理は計算されません。そのため、pprof を使うと真のボトルネックとなる処理が分からないことが多々有りました。 そこを改良したのが fgprof となります。fgprof を使うことで cpu 上で行われない処理(off-cpu)の処理を測定し、真のボトルネックを見つけることが可能になりました。すごいツールです。 使用例 go-chi で以下のようなサーバーを作成して、どのようにプロファイルされるかを見ていきます。 package main import ( "context" "net/http" "github.com/go-chi/chi" ) func main() { r := chi.NewRouter() r.Get("/", func(w http.ResponseWriter, r *http.Request) { // cpuを止める処理 cpuIntensiveTask() // 良くわからない関数 weirdFunction() // なんらかの network request slowNetworkRequest(r.Context()) }) panic(http....

2020/08/04(作成日) · 2022/09/26(更新日)

cloud run と app engine の個人的な比較

背景 cloud run + nuxtjs でサイトを作ってみたので、普段業務で使っている appengine と比較して感じたことなどを書いて行きます。 ※この記事は書かれてから 1 年以上経っているため、当時の気持ちぐらいに取らえてください。 公式の見解は? そもそも公式ドキュメントでは、どのように使い分けるよう書いてあるか見ていきます。 この記事を書いている段階では、こちらの公式ドキュメントにサーバーレスの選択について書いてあります。ぱっと見分かりやすいのが下の図ですね。 こちらを見る限りは、単純(少数)な api なら cloud function。複雑(複数)な api やアプリケーションなら基本的に appengine を使っておいて、cloud run は言語などが対応していない時の appengine の代替案かなという印象を受けます。 flexible 環境は論点にも上がらない感じですね。 使用しての個人的な比較 それでは実際に使用してみての比較について書いていきます。個人的な感想なので、使っていない anthos 周りについては書いてありません。 build & deploy サーバーレスアプリケーションにおいて、ci & cd でどのようにサーバに反映されるかはかなり重要だと思うのでまずはここから。 最初に cloud build の公式サンプルを見ていきます。 appengine の build & deploy steps: - name: "gcr.io/cloud-builders/gcloud" args: ["app", "deploy"] timeout: "1600s" github の push でトリガーされて、これで deploy 完了というのはほれぼれしますねー。 個人的な難点としては appengine のデプロイルールに縛られることだと思います。app.yml の設定、依存関係の解決、ディレクトリ構造。。。少し凝ったことをすると意外とハマりやすい印象です。 はまればすごい楽というイメージです。 cloud run の build & deploy steps: # Build the container image - name: "gcr....

2020/07/27(作成日) · 2022/09/26(更新日)